Un proyecto Next.js enviado a un freelancer por un supuesto cliente de Fiverr incluía un token de npm que permitía descargar una dependencia privada invisible en el registro público. El código se activaba después, cuando el desarrollador iniciaba el servidor de desarrollo: una configuración de Tailwind cargaba un plugin, y este requería el paquete oculto dentro del proceso de Node.js.
El desarrollador que describió el caso en DEV Community no ejecutó el proyecto en su ordenador. Lo examinó en un entorno aislado de solo lectura y comunicó el paquete a npm. La maniobra no dependía de un instalador abiertamente malicioso ni de código ofuscado a simple vista. Su pieza decisiva era un token en .npmrc, incluido junto al proyecto y capaz de abrir el acceso a un paquete que devolvía un error 404 a quienes no tenían credenciales.
El alcance va más allá de ese encargo: Corgea documentó una campaña con paquetes públicos que imitaban plugins de Animate.css para Tailwind, mientras que pkgwarden describió una red de 29 paquetes y un repositorio de evaluación laboral preparado para entregar el token. Los informes no presentan exactamente el mismo inventario ni la misma fecha de comprobación; juntos muestran una táctica que se adaptaba después de las retiradas.
Una cadena que esperaba al servidor de desarrollo
En el proyecto recibido por el freelancer, el archivo frontend/package.json declaraba tailwind-animationlab como dependencia de desarrollo. El plugin se había publicado en npm el 28 de septiembre, la misma fecha en que, según la publicación de DEV Community, se había modificado por última vez la configuración de Tailwind. Ningún componente de la aplicación usaba sus clases: bastaba con que Tailwind lo cargara.
Dentro del plugin, src/motion.js requería @jasperquinn/postcss-motion-helpers. Ese paquete no estaba disponible públicamente. Sin embargo, el archivo frontend/.npmrc contenía un token de acceso de npm. Al instalar las dependencias, npm podía utilizarlo para descargar el paquete privado; luego, al ejecutar npm run dev, Next.js cargaba la configuración de Tailwind y esta abría el plugin y su dependencia.
El orden importa: descargar el paquete y ejecutar su código eran momentos distintos. Corgea y pkgwarden explican que las versiones examinadas no necesitaban scripts de instalación; la carga se producía cuando el servidor o el proceso de compilación leía la configuración. Por eso, la opción --ignore-scripts no habría frenado esta cadena: evitaba scripts de ciclo de vida, pero no impedía que la configuración requiriese el plugin al arrancar.
flowchart TD A["Proyecto con .npmrc"] --> B["npm install usa el token"] B --> C["Descarga el paquete privado"] C --> D["npm run dev inicia Next.js"] D --> E["Tailwind carga su configuración"] E --> F["El plugin requiere el paquete oculto"] F --> G["Código dentro del proceso Node.js"]
La cadena explica por qué una revisión limitada al código de la aplicación podía no encontrar nada. El freelancer dijo que el backend, los modelos de MongoDB, las llamadas a Gemini y los componentes parecían limpios. La dependencia peligrosa entraba desde fuera del código visible en esos archivos y se ejecutaba al cargar la configuración.
Una oferta laboral como mecanismo de entrega
El encargo de Fiverr tenía señales que, vistas en conjunto, resultaban sospechosas: no incluía capturas ni registros de los errores que supuestamente había que corregir, el primer archivo era una presentación para revisión interna e inversores y el código llegó en un ZIP compartido por Google Drive, no desde un repositorio de GitHub. Además, el README describía una aplicación React con Vite y Clerk, mientras el proyecto contenía Next.js 16 y un inicio de sesión basado en JWT. Aun así, las instrucciones repetían que había que instalar y arrancar la aplicación.
Pkgwarden documentó otra variante del señuelo: una evaluación técnica atribuida a «Nodveta», publicada en Torre.ai, que llevaba a un repositorio privado de GitHub. Allí, el archivo web/.npmrc guardaba el token y el proyecto incluía archivos dirigidos a agentes de programación. Según pkgwarden, AGENTS.md y CLAUDE.md indicaban al agente que consultara documentación dentro de node_modules, lo que empujaba a instalar dependencias. El blanco, por tanto, podía ser tanto la persona candidata como el agente que trabajaba en su entorno.
El parecido entre el encargo descrito en DEV Community y el patrón de entrevistas falsas señalado por pkgwarden no demuestra quién estaba detrás del caso de Fiverr. El autor de la publicación dijo expresamente que no podía atribuir la campaña a un actor. Pkgwarden también evitó adjudicarla a un grupo y la describió como consistente con el método conocido como «Contagious Interview».
Retiradas rápidas, reemplazos y cifras distintas
Según la cronología de DEV Community, el autor informó a npm sobre tailwind-animationlab el 29 de octubre, alrededor del mediodía en Sri Lanka. npm reemplazó ese paquete y tailwind-keyframes con versiones de seguridad esa noche, y retiró el helper privado @jasperquinn/postcss-motion-helpers. A las pocas horas apareció otro helper privado; npm también lo retiró el 30 de octubre. GitHub Trust & Safety comunicó al autor que «one or more violations of npm's Open-source Terms have occurred».
one or more violations of npm's Open-source Terms have occurred
— GitHub Trust & Safety
La retirada no cerró la actividad. El autor de DEV Community encontró el 2 de noviembre una versión 2.0.10 de tailwind-kinetics que dependía de un helper distinto, además de otros dos paquetes privados que no podían verse en el registro público. Corgea, en su actualización del 30 de octubre, también registró el cambio a nuevos ámbitos privados y paquetes públicos publicados o actualizados tras las primeras medidas de npm.
Los recuentos dependen del perímetro y del momento de cada investigación. DEV Community identificó al menos 19 paquetes adicionales con código basado en la misma plantilla, aparte de los que describe en su caso. Corgea amplió su inventario a 43 paquetes públicos y siete dependencias privadas asociadas al patrón. Pkgwarden, en cambio, siguió una agrupación de 29 plugins y 40 versiones, y señaló que 26 de esos paquetes seguían instalables el 16 de octubre. No son cifras intercambiables: las publicaciones cubren fechas, paquetes y subgrupos distintos.
También varía lo que podía comprobarse del payload. Los paquetes públicos examinados por Corgea y pkgwarden parecían plugins funcionales y no contenían scripts de instalación ni código ofuscado; la pieza privada era la que no podía inspeccionarse desde el registro público. LPM Firewall, al evaluar [email protected], dijo que el código disponible mostraba una ruta de generación de CSS, pero que el comportamiento del helper importado seguía sin resolverse porque no tenía su código. Por tanto, los informes describen una cadena diseñada para cargar código oculto; no verifican qué acciones concretas ejecutaba ese código en el equipo.
El coste de confiar en un proyecto ajeno
El intercambio es especialmente delicado para quienes aceptan trabajos freelance o pruebas técnicas. Para evaluar el encargo, necesitan ejecutar una aplicación que no controlan; aquí, hacerlo en el ordenador habitual habría entregado al código la misma capacidad de acceso a archivos que tenía el usuario. El autor de DEV Community advirtió que campañas similares habían buscado contraseñas guardadas, tokens de API y carteras de criptomonedas, pero no afirmó haber observado esas acciones en el payload privado de este caso.
Para las empresas, el riesgo también alcanza a los entornos de desarrollo y a los agentes de programación. Pkgwarden señaló que la documentación añadida al repositorio estaba pensada para orientar a herramientas de IA hacia la instalación y el arranque. Un agente con acceso al entorno del candidato no convierte un repositorio dudoso en confiable: puede seguir instrucciones que desencadenen la misma carga que ejecutaría una persona.
El patrón deja una tensión práctica: los controles centrados en los scripts de instalación no cubren código que se ejecuta cuando una herramienta carga una configuración. Tampoco basta con que el paquete público parezca pequeño, funcional y legible si depende de un paquete privado que el análisis externo no puede recuperar. En este caso, la instalación autenticada ocultaba la relación entre ambos componentes, y el inicio de Next.js completaba la ejecución.
El autor del caso evitó instalar el proyecto en su equipo y usó un entorno aislado para leer los archivos sin ejecutar comandos. DEV Community recomendó revisar especialmente los archivos de configuración que se cargan durante el desarrollo, tratar un token en un .npmrc recibido con un proyecto ajeno como una señal de alerta y comprobar dependencias desconocidas. Para quienes ya hubieran ejecutado una evaluación afectada, pkgwarden aconsejó tratar el equipo como comprometido y rotar las credenciales a las que podía acceder.
El punto de control no era una función visible de la aplicación ni un instalador que se ejecutara de inmediato: era la combinación de una credencial incluida en el proyecto, un paquete privado inaccesible para terceros y una configuración que lo cargaba al arrancar.
Fuentes: DEV Community, Corgea, pkgwarden, LPM Firewall