Blog / Guías prácticas

GhostAction: borrar un secreto no es revocarlo

GhostAction rebusca secretos antiguos. Separe la rotación de la limpieza del historial de Git y verifique que las credenciales expuestas y la vía de inyección en los workflows están cerradas.

Estudios de doctorado en Seguridad de la Información completadosDefensa universitaria superada · Defensa final de la tesis pendiente

El archivo está limpio. ¿Qué dice el emisor de la credencial?

Ha borrado el secreto. ¿Ha revocado su acceso? GhostAction vuelve urgente esa pregunta: una cuenta de mantenedor comprometida puede introducir un workflow que busque en los commits antiguos además de en los archivos actuales. Un árbol de trabajo limpio no puede decirle si la credencial que encuentra sigue funcionando. Esa decisión corresponde al servicio que la emitió.

La campaña de octubre de 2026 es el punto de partida, pero lo realmente útil es una forma de cerrar el incidente con evidencias. Separo tres preguntas: dónde queda material secreto, si el emisor todavía lo acepta y si el atacante puede introducir otro workflow. Este análisis se basa en investigación pública y en la documentación de GitHub; aquí no se ha ejecutado ningún payload de la campaña. [1][2]

El historial de Git se convierte en entrada del runner comprometido

StepSecurity describe un security-audit.yml malicioso enviado directamente con la identidad de un mantenedor comprometido. Su checkout solicita el historial completo. Después, el script usa git log -p --all para examinar los parches. También intenta recoger los valores de los secretos de Actions configurados insertando los nombres que descubre en los workflows existentes. Los nombres indican qué pedir; los valores son lo que busca el atacante. [1]

Observe el historial ilustrativo de abajo. El commit B elimina el token del archivo más reciente, mientras que el commit A todavía lo registra. Una búsqueda que recorra el historial puede, por tanto, recuperar el texto antiguo. Aun así, lo que obtiene el atacante está limitado por las referencias descargadas, los patrones que coinciden y los límites de salida del payload. No convierta esa capacidad en la afirmación de que se extrajeron con éxito todos los secretos históricos.

Illustrative repository history; no real credential

A: config.env contains API_TOKEN=DEMO_NOT_A_REAL_TOKEN
B: config.env no longer contains API_TOKEN

Current file: absent
Earlier commit: present
Issuer status: a separate question

¿Puede un secreto recuperado seguir autenticando?

Que se pueda recuperar y que siga siendo válido son propiedades independientes. Un token antiguo puede seguir visible después de revocarse sin conceder ya acceso. Un token también puede desaparecer del repositorio que usted controla y seguir siendo utilizable desde la copia de otra persona. GitHub recomienda revocar o rotar primero las credenciales expuestas; reescribir el historial se ocupa de las copias restantes y exige coordinación con clones, forks y referencias. [2]

Esta distinción cambia mi forma de leer las estadísticas de limpieza. El número de repositorios que contienen texto de secretos antiguos mide el residuo público, no el número de credenciales que un emisor seguiría aceptando. También cambia la prueba de aceptación: sustituir una variable de CI no basta si la credencial anterior no se ha desactivado en su emisor. Regístrelo por separado de si las compilaciones funcionan con la nueva.

                              Old credential accepted?
                              Yes                 No
Secret text recoverable       Access remains       Residual disclosure
Secret text no longer found   Access may remain    Both checks needed

A repository scan cannot answer the issuer-status column.

¿Qué control detiene realmente el siguiente workflow?

Los requisitos de revisión solo ayudan allí donde se aplican. El control de aprobación de GitHub para los workflows procedentes de forks públicos se refiere a esa vía de contribución; no es una puerta de aprobación universal para el push directo de un mantenedor. StepSecurity informa de que una puerta de aprobación detuvo determinadas ejecuciones observadas, pero esa observación no demuestra que la configuración para forks proteja a todos los repositorios frente a esta campaña. [1][3]

En una rama protegida, exija pull requests y la revisión del code owner correspondiente, y después compruebe quién puede saltarse la regla. Una entrada de CODEOWNERS para .github/workflows/ define la responsabilidad; la regla de la rama hace obligatoria esa revisión. Proteja también el propio archivo CODEOWNERS y examine las demás ramas cuyos workflows de push pueden recibir secretos. Proteger solo main no cubre todas las rutas de ejecución de workflows. [4][5]

Un token de repositorio de solo lectura puede acompañar al robo de secretos

Reducir los permisos de GITHUB_TOKEN es útil, pero no revoca una credencial de nube que se pasa por separado a un job. El workflow observado podía funcionar con el contenido del repositorio en solo lectura mientras recogía otras credenciales. Por eso, una revisión de permisos debe inventariar tanto el token integrado como cada secreto independiente que se pone a disposición de la ejecución. [1]

Mi revisión sigue una cadena concreta: quién puede modificar el workflow, qué evento lo inicia, qué identidad y qué secretos recibe el job y con qué destinos puede comunicarse. En un job de publicación, la pregunta es si quien escribe un workflow puede convertir ese job en un lector de credenciales. Restringir la escritura en el repositorio solo responde a una parte de esa cadena. Es una pregunta de revisión de la arquitectura, no la afirmación de que cada runner expuso todos los secretos.

Contenga el acceso antes de pulir el historial del repositorio

Conserve la revisión del workflow, los identificadores de las ejecuciones y los registros de auditoría pertinentes antes de que la limpieza elimine el contexto. Corte la vía de ejecución maliciosa y revoque la credencial del mantenedor comprometido. Después, inventaríe los secretos actuales de los jobs y las credenciales históricas dentro del alcance de la exposición, asigne cada una a un responsable y deje constancia de su revocación en el servicio emisor. Cuando no se pueda determinar la validez, trátela como un asunto sin resolver en lugar de declarar limpio el repositorio. [1][2]

Una credencial de sustitución debe introducirse por una vía de ejecución de confianza. De lo contrario, el mismo workflow comprometido puede leerla en la siguiente ejecución. La limpieza del historial conlleva su propio trabajo de coordinación y no puede recuperar las copias que un atacante ya haya obtenido. En el caso de las claves que pueden crear sesiones u otras credenciales, revise también ese acceso derivado; desactivar el secreto original no demuestra por sí solo que no se haya establecido un acceso independiente.

Pida un registro de cierre, no una captura de pantalla limpia

Un registro de corrección debe permitir a otro ingeniero distinguir el trabajo completado de las suposiciones. Para cada credencial expuesta, conserve su identificador no secreto, su responsable, el sistema emisor, la ventana de exposición, la evidencia de la revocación y el estado del despliegue de la sustitución. Registre cómo se contuvo la identidad usada para la inyección y cómo se restringió la vía de los workflows. La plantilla siguiente es un artefacto de revisión propuesto, no la transcripción de este incidente.

La pregunta del comprador se vuelve precisa: ¿puede su equipo demostrar que el acceso expuesto anteriormente ya no se acepta y que la sustitución no puede filtrarse por la misma vía? Esa es la evidencia que pediría en una verificación de la corrección. Marca la diferencia entre cerrar un ticket y cerrar el acceso que se pretendía eliminar.

Credential ID / owner / issuer: ____________________
Exposure scope and evidence: _______________________
Old credential disabled at issuer: _________________
Replacement deployed through trusted workflow: _____
Compromised maintainer access contained: ____________
Other credentials or sessions investigated: _________
Remaining copies / uncertainty / responsible owner: _

Fuentes

¿Necesita que se compruebe esto en su propio producto?

Corrección y verificación

¿Quiere aprender a encontrar vulnerabilidades como esta por su cuenta?

Curso individual de revisión de código seguro
Todos los artículos

08Contacto

¿Va a lanzar algo que trata datos de usuarios?

Envíeme un breve resumen. Respondo en un plazo de tres días con preguntas o un esbozo de propuesta, y el precio se acuerda por escrito antes de empezar.