GitHub y wfx-loot: pasos para detectar y contener el robo de secretos

GitHub y wfx-loot: pasos para detectar y contener el robo de secretos

La campaña wfx-loot alcanzó 4.837 cuentas comprometidas y probó permisos de escritura en 61.764 repositorios de GitHub; en al menos 1.835 ejecutó código que robó secretos y credenciales de nube, según Aikido. La señal inicial es una pull request titulada docs: dependency audit notes, pero encontrarla no basta para saber si el ladrón se ejecutó.

Los atacantes usaron credenciales robadas para tantear repositorios, incluso aquellos a los que las cuentas accedían como colaboradoras. Después inyectaban un script en flujos de GitHub Actions, scripts de shell o un hook de instalación de npm, y solían borrar los cambios y los registros. La ausencia de un registro no descarta la filtración: los investigadores recomiendan tratar los secretos como expuestos si el payload llegó a ejecutarse.

1. Busca las señales en cada repositorio

  1. Revisa todos los repositorios en los que tu cuenta o tus cuentas de automatización podían escribir desde el 10 de noviembre. Aikido indica que la campaña comenzó aproximadamente a las 12:45 UTC de ese día. Incluye repositorios de organizaciones y accesibles como colaborador, no solo los que pertenecen a tu usuario. El alcance siguió los permisos de escritura.

  2. Busca una rama wfx-docs y una pull request titulada docs: dependency audit notes. También presta atención a ramas breves con nombres como chore/ seguido de ocho caracteres aleatorios, o ci-check- seguido de cuatro cifras. Esa pull request sirve como prueba de acceso: por sí sola no es el payload, pero Aikido considera comprometida la cuenta que la abrió, aunque no haya más cambios.

  3. Examina el historial de commits en busca de ci: refresh build cache, chore: add ci helper y chore: add dependency audit workflow. También aparecen en los indicadores ci: restore y ci: cleanup, usados en la limpieza posterior. Los mensajes de commit pueden delatar la inyección, aunque el cambio ya se haya revertido.

  4. Inspecciona los archivos y cambios asociados: una modificación de un flujo existente, un nuevo archivo en .github/workflows/ con nombre parecido a build-audit-, o un script oculto .ci- conectado a un hook en package.json. StepSecurity también observó el código añadido a scripts de shell que ya ejecutaban los flujos. No te limites, por tanto, a revisar los archivos de workflow.

2. Averigua si el código llegó a ejecutarse

  1. En el historial de Actions, revisa las ejecuciones alrededor del commit sospechoso y busca saltos en la numeración. Aikido describe la falta de un número de ejecución como una señal más fiable que buscar artefactos: el atacante borraba ejecuciones y registros, en ocasiones en menos de un minuto. Un hueco puede ser la única huella visible.

  2. No des por limpia una ejecución porque no encuentres artefactos con nombres como wfx-loot-, entradas de caché con wfx- o resúmenes marcados con WFX-BEGIN. Aikido explica que esos métodos estaban desactivados en las muestras de esta campaña que analizó; además, el envío podía realizarse por otros canales. La falta de esos indicadores no demuestra que no se extrajeran datos.

  3. Si el repositorio publicó paquetes automáticamente, comprueba si alguno de los cambios se propagó. Aikido identificó digitalelvis/neuronai-studio 3.14.3 en Packagist y github.com/onuragtas/docker-env en las versiones v1.0.278 y v1.0.280. The Hacker News también señala el módulo github.com/vkuznet/gocurl en la pseudoversión v0.0.0-20261111095532-8d5aad0cb0da. En este último caso, su análisis indica que el flujo malicioso no se había ejecutado. Comprueba la versión exacta antes de actuar.

  4. Valora por separado las máquinas que instalaron o abrieron el paquete Packagist 3.14.3: Aikido aconseja tratarlas como comprometidas. The Hacker News precisa que una instalación normal de Composer no ejecuta el ladrón, pero sí puede hacerlo un npm install dentro del directorio del paquete. Para las versiones afectadas del módulo Go, el payload estaba únicamente en un archivo de workflow; Aikido y The Hacker News señalan que el código Go y los binarios publicados no cambiaron, aunque recomiendan retirar esas versiones.

GitHub y wfx-loot: pasos para detectar y contener el robo de secretos
© Aikido Security

3. Contén el acceso y rota lo que pudo exponerse

  1. Si confirmas que se ejecutó el payload, considera expuestos todos los secretos, variables, tokens y roles de nube a los que podían acceder esos flujos. Rótalos de inmediato. El script estaba diseñado para recopilar credenciales de GitHub Actions, AWS, Azure y Google Cloud, entre otras, además de archivos de configuración, claves SSH y credenciales de herramientas de desarrollo. Limita la rotación al conjunto correcto, pero no lo reduzcas por intuición.

  2. Revoca las credenciales de las cuentas y automatizaciones que abrieron las pull requests o empujaron los commits sospechosos. SafeDep, citado por The Hacker News, recomienda revocar tokens, autorizaciones de aplicaciones OAuth, claves SSH y sesiones, además de activar la autenticación en dos factores. Revisa especialmente cuentas de bots con permisos de escritura: StepSecurity observó commits publicados como cuentas automatizadas.

  3. Busca señales de persistencia en los proveedores de nube a los que tenía acceso el flujo. The Hacker News recomienda revisar en Entra ID credenciales federadas con prefijo wfx-ci-; en AWS CloudTrail, sesiones AssumeRoleWithWebIdentity o nombres wfx- seguidos de eventos CreateAccessKey o UpdateAssumeRolePolicy; y en GCP, llamadas GenerateAccessToken y SignJwt desde la identidad de carga de trabajo de GitHub. Aikido describe cambios que podían mantener el acceso incluso después de rotar secretos.

  4. Comprueba también los registros de HashiCorp Vault y los roles de nube asociados a los flujos afectados. The Hacker News sugiere buscar inicios de sesión JWT desde el emisor OIDC de GitHub en Vault. Si un rol o política se modificó, restaura su configuración legítima y elimina credenciales no autorizadas; no des por resuelto el incidente solo porque los tokens antiguos ya no funcionen.

  5. Si aparecen cambios maliciosos, conserva los datos disponibles para la investigación antes de limpiar el repositorio, y elimina o revierte el código inyectado. Comprueba ramas, flujos, scripts de shell y hooks de npm. La reversión del atacante no es una reparación: pudo haber ejecutado el código y extraído credenciales antes de borrar sus rastros.

Errores que pueden dejar el acceso abierto

No confundas la pull request de prueba con el payload. La primera prueba que una cuenta podía escribir en el repositorio; la carga maliciosa llegaba después y no en todos los casos. A la inversa, que solo encuentres la pull request no significa que la cuenta sea segura: Aikido considera comprometida la cuenta que la abrió.

No confíes únicamente en que los cambios hayan desaparecido, en que el flujo figure como correcto o en que falten artefactos. Los atacantes revertían commits y borraban ejecuciones, y StepSecurity documentó que el código también podía esconderse en scripts ya usados por la automatización. Verifica el historial y el acceso a la nube, no solo el estado actual del árbol de archivos.

Por último, no apliques la misma conclusión a todos los paquetes. Packagist 3.14.3 puede ejecutar el código si se lanza npm install en su directorio; las versiones de docker-env contienen el payload en un workflow, no en el código Go ni en los binarios, según Aikido. La versión de gocurl señalada por The Hacker News también lleva el código en un workflow que no se había ejecutado. Las respuestas deben seguir esas diferencias, sin dejar de bloquear las versiones identificadas.

Fuentes: TechRadar, BleepingComputer, Aikido Security, StepSecurity, The Hacker News