Mika Ayenson, PhD

Abuso de la tubería CI/CD: el problema que nadie está observando

Cómo construimos una plantilla de CI de código abierto y directa que emplea la extracción de señales y el razonamiento de LLM para detectar abusos de CI/CD en GitHub Actions, GitLab CI y las canalizaciones de Azure DevOps.

Preámbulo

En 2025 y 2026, observamos un patrón que se desarrollaba en toda la industria. Los atacantes dejaron de atacar directamente los servidores de producción y empezaron a atacar la automatización que se despliega en ellos. Credenciales de desarrollador comprometidas, un archivo de flujo de trabajo modificado y, de repente, todos los secretos en un entorno CI/CD se transmiten a un punto final controlado por el atacante. Vimos esto en incidentes que involucraron grandes proyectos de código abierto, compañías de Fortune 500 y herramientas de infraestructura crítica.

La cadena de ataques es engañosamente simple:

Credenciales de desarrollador robadas → archivo de flujo de trabajo modificado → secretos de CI recolectados → Movimiento lateral a la nube y producción

Hoy en día estamos abriendo el código de código cicd-abuse-detector, una plantilla de CI directa que emplea extracción de señales basadas en regex y análisis LLM para detectar cambios sospechosos en las canalizaciones CI/CD. Funciona en GitHub Actions, GitLab CI y Azure DevOps, y está diseñado en torno a las técnicas de ataque reales documentadas en la investigación de seguridad pública.

Conclusiones clave

  • Los entornos CI/CD son objetivos de alto valor porque un único flujo de trabajo comprometido puede extraer credenciales en la nube, tokens de registro de empaquetados, claves de firma de código, claves de despliegue y tokens OIDC simultáneamente
  • La herramienta extrae 50+ señales regex y metadatos de diferenciales, y luego las pasa con el diferencial completo a Claude para un análisis estructurado de amenazas. Sin Python, sin dependencias más allá de bash y la línea de comando Claude Code
  • Se probaron patrones de detección contra kits de herramientas ofensivos como Nord Stream y Gato-X, y contra incidentes reales como ArtiPACKED y HackerBot-Claw
  • El proyecto incluye 19 diferenciales maliciosos y cuatro diferenciales de ejemplo benignos modelados a partir de incidentes específicos, y un conjunto de pruebas automatizado que valida cada señal

Por qué las tuberías CI/CD son un objetivo principal

Si dedicas tiempo a revisar GitHub Actions o configuraciones de GitLab CI, puede que notes cuánta confianza se concentra en estos archivos. Un flujo de trabajo típico de despliegue tiene acceso a credenciales AWS, tokens de publicación npm, contraseñas de Docker Hub y un token de GitHub con licencias de escritura, todo al mismo tiempo. La superficie de ataque no es un servidor con un CVE, es un archivo YAML.

Recolección de credenciales a gran escala

Un atacante con credenciales de desarrollador robadas modifica un flujo de trabajo para exfiltrar secretos disponibles en el entorno de CI. La campaña GhostAction en septiembre de 2025 demostró esto a gran escala, comprometiendo 327 usuarios de GitHub en 817 repositorios. Se robaron 3.325 secretos mediante archivos de flujo de trabajo inyectados que enviaban credenciales POST a los endpoints atacantes.

El gusano npm Shai-Hulud fue más allá. Este ataque autopropagante recolectaba GitHub Personal Access Tokens mediante token gh auth, ejecutaba TruffleHog para reconocimiento secreto y empleaba tokens comprometidos para inyectar silenciosamente código malicioso en otros paquetes propiedad del mismo desarrollador. Solo en la primera oleada se publicaron más de 46.000 paquetes maliciosos.

Explotación de disparadores privilegiados

El disparador pull_request_target es una de las características más peligrosas de GitHub Actions. A diferencia de un disparador pull_request normal, ejecuta flujos de trabajo en el contexto del repositorio base con acceso a secretos, pero puede ejecutar código desde un fork no confiable. La investigación de Orca "Pull Request Nightmare" demostró esto frente a repositorios mantenidos por Google, Microsoft y NVIDIA.

En febrero de 2026, una campaña automatizada llamada HackerBot-Claw escaneó sistemáticamente los repositorios públicos en busca de esta configuración exacta. Empleaba cinco técnicas diferentes de explotación, incluyendo funciones de Go envenenadas de init() , inyección de comandos de nombre de salto, inyección basada en nombres de archivo, inyección directa de scripts e inyección de prompts de IA contra revisores de código basados en Claude. En el caso más grave, el repositorio Trivy de Aqua Security fue completamente comprometido, lo que llevó a un ataque a la cadena de suministro aguas abajo que expuso 33.000 secretos en casi 7.000 máquinas. Según se documentó, este ataque a la cadena de suministro fue posible gracias a tokens comprometidos que eran válidos semanas luego de ser robados inicialmente.

El resto de la taxonomía

Más allá de la obtención de credenciales y la explotación de desencadenantes, el modelo de amenazas abarca cuatro categorías adicionales que aparecen de forma constante en la investigación pública:

  • Escalada de licencias, donde agregar licencias: write-all o id-token: write amplía el radio de explosión de cualquier compromiso
  • Segmentación de runners, redirigir trabajos a runners autoalojados que a menudo tienen acceso a la red a la infraestructura interna, o especificar imágenes de contenedores controladas por atacantes
  • Manipulación de la cadena de suministro mediante referencias de acciones mutables (usando versiones @main en lugar de SHA), ejecución remota de scripts (curl | bash), intercambios de registros de archivos de bloqueo y envenenamiento de dependencias
  • Evasión de defensa mediante manipulación de la marca de tiempo de compromiso, haciendo que los archivos maliciosos parezcan antiguos y de confianza. KL4R10N documentado esta técnica en campañas vinculadas a la RPDC donde retrocede la infraestructura de referencia de commits que no existía en la fecha declarada

Cada uno de estos se corresponde con técnicas específicas de MITRE ATT& CK: T1552 (Credenciales no seguras), T1195 (Compromiso de la cadena de suministro), T1070.006 (Timestomp) y T1059 (Intérprete de comandos y scripts).

Cómo funciona el detector

Queríamos que las plantillas funcionaran sin necesidad de Python, runtimes personalizados ni dependencias complejas. Todo se ejecuta en utilidades estándar de shell en un runner ubuntu-latest por defecto, y la única herramienta instalada es la Claude Code CLI vía npm, que gestiona autenticación, retries y enrutamiento de modelos.

Fase 1: Filtro y diferenciales

Cuando se abre una solicitud pull (o un push llega a una rama protegida), el flujo de trabajo identifica los archivos modificados a través de tres niveles de rutas relevantes para CI/CD. El primer nivel cubre archivos de CI núcleo como definiciones de flujos de trabajo, configuraciones de pipelines y Makefiles. La segunda abarca artefactos de construcción y liberación como Dockerfiles, manifiestos de paquetes, archivos de bloqueo y scripts de firma o despliegue. El tercer nivel recoge configuraciones de entorno de desarrollo como .vscode/tasks.json y .devcontainer archivos.

Cada archivo se diferencia individualmente y tiene un límite de 10.000 caracteres. Hacemos esto por archivo en lugar de globalmente porque un único límite en el diferencial combinado es un vector de bypass. Un atacante puede rellenar un cambio malicioso en el flujo de trabajo con una gran edición benigna de Dockerfile para llevar el exploit más allá del límite de caracteres.

Etapa 2: Extracción de señales

Antes de que el LLM detecte nada, los patrones regex 50+ escanean cada diferencial en busca de patrones conocidos como peligrosos. Estas señales son de advertencia. Nunca bloquean el análisis, pero proporcionan al LLM un resumen de amenazas preseleccionado. Algunos ejemplos:

SeñalPatrónLo que atrapa
secrets_context${{.*secrets.Interpolación secreta directa en flujos de trabajo
pull_request_targetpull_request_targetEl disparador peligroso que otorga secretos al código de relaciones públicas
checkout_refref:.*github.event.pull_request.head.(sha|ref)Código PR no confiable verificado en un contexto privilegiado
double_base64base64.*|.*base64Doble codificación para evadir el enmascaramiento de logarítmicas (técnica Nord Stream)
ld_preloadLD_PRELOADEjecución arbitraria de código mediante inyección de variables de entorno
vscode_auto_taskrunOn.*folderOpenTarea de VS Code que se ejecuta al abrir una carpeta (Entrevista Contagiosa)

La lista de señales se basa en herramientas adversariales reales, incluyendo Nord Stream y Gato-X, y se prueba contra diferenciales de ejemplo maliciosos 19 modelados a partir de incidentes específicos.

El detector funciona de forma idéntica en GitHub Actions, GitLab CI y Azure DevOps. Aquí tienes las detecciones disparando en cada plataforma:

Fase 3: Análisis de LLM

El resumen de la señal, el diferencial completo, el perfil del autor y los metadatos de commit se agrupan y envían a Claude a través de la CLI de código de Claude. El prompt de análisis guía al modelo por varias áreas:

  1. Comprensión diferencial y evaluación de riesgos por expediente
  2. Interpretación de señales con contexto (una señal por sí sola no es un veredicto)
  3. Análisis temporal para commits retroactivos
  4. Evaluación del fideicomiso de autores empleando la antigüedad de la cuenta, historial de contribuciones y membresía en la organización
  5. Calibración de severidad frente a una tabla de combinación de señales con 60+ entradas
  6. El reconocimiento de falsos positivos (por ejemplo, cURL para descargar herramientas conocidas no es exfiltración)
  7. Recomendaciones concretas y accionables ("Fijar acciones/node@main de configuración a un SHA específico" en lugar de "revisar cuidadosamente")

El resultado es un veredicto JSON estructurado que contiene gravedad, confianza, razonamiento, pruebas y recomendaciones, todo validado frente a un Esquema JSON.

Fase 4: Alerta y puerta

Según la gravedad del veredicto, el flujo de trabajo publica un resumen de pasos, crea un problema, envía una notificación en Slack y, opcionalmente, falla la comprobación de PR si la gravedad alcanza un umbral configurado.

Las alertas en Slack y GitHub Issues resuelven el problema de notificaciones inmediatas, pero no te dan un historial consultable. Cada veredicto que produce el detector (por ejemplo, benigno, sospechoso o malicioso), pueden enviar opcionalmente a Elasticsearch como un documento estructurado en los logs-cicd.abuse-default flujo de datos. El flujo de trabajo agrupa el veredicto junto con los metadatos CI/CD (plataforma, repositorio, actor, tipo de evento, URL de ejecución) en un único índice que abarca las tres plataformas soportadas.

Aquí es donde la correlación entre plataformas se vuelve práctica. Una alerta de Acciones de GitHub y una alerta de CI de GitLab del mismo actor aterrizan en el mismo flujo de datos, consultables en un solo ES|Declaración QL:

FROM logs-cicd.abuse-* 
WHERE verdict.verdict IN ("malicious", "suspicious") AND @timestamp > NOW() - 7 days 
EVAL platform = cicd.platform, repo = cicd.repository, actor = cicd.actor, severity = verdict.severity
KEEP @timestamp, platform, repo, actor, severity
SORT @timestamp DESC

El esquema incluye cicd.platform, cicd.repository, CICD.Actor y el objeto completo del veredicto (veredicto, gravedad, confianza, resumen, razones, pruebas), facilitando la elaboración de reglas de detección. Una campaña coordinada que afecta a varios repositorios en una hora, un reincidente marcado en varias plataformas, o un pico de hallazgos críticos que justifique una página de respuesta a incidentes pueden correlacionar.

Validación contra ataques reales

Para validar la cobertura, comparamos nuestros patrones de detección con el código fuente real de herramientas ofensivas, investigaciones publicadas y autopsias públicas.

Nord Stream: coincidencia literal de cargas útiles

Nord Stream es la herramienta de extracción de secretos CI/CD de código abierto de Synacktiv, que soporta GitHub, GitLab y Azure DevOps. Extrajimos la fuente del generador YAML (nordstream/yaml/github.py) y comparamos sus plantillas de salida con nuestros diferenciales de ejemplo.

  • La plantilla de payload de GitHub emplea env -0 | awk -v RS='0' '/^secret_/ {print $0}' | base64 -w0 | base64 -w0. Nuestro nord-stream-pipeline-exfil.diff contiene esta línea literalmente, y nuestras señales double_base64, env_null_dumpy env_secret_grep disparan.
  • La plantilla OIDC de Azure emplea azure/login@v1 con licencias id-token: write seguidos de get-access-token | base64 -w0 | base64 -w0cuenta de az. Nuestro diferencial captura exactamente este flujo y activa cloud_auth_action y id_token_write.
  • Las técnicas de la tubería Azure DevOps (addSpnToEnvironment para exposición a credenciales SPN, DownloadSecureFile para robo de archivos seguros, parcheo de código de tareas SSH mediante modificación ssh.js ) están todas presentes en nord-stream-azure-devops.diff y detectadas por señales específicas de la plataforma.

ArtiPACKED: la condición de la raza de artefactos

La investigación de ArtiPACKED de la Unidad de Palo Alto 42 mostró que subir todo el directorio de préstamo como artefacto filtra el archivo .git/config que contiene el GITHUB_TOKEN. Con la API de artefactos v4 permitiendo descargas a mitad de ejecución, un atacante puede extraer y usar el token antes de que el trabajo se complete.

Nuestro artifact-token-leak.diff modela exactamente este patrón, usando upload-artifact con path: . (todo el espacio de trabajo). La señal de upload_artifact la detecta y el LLM evalúa si el alcance de subida incluye el directorio .git .

GITHUB_ENV inyección: LD_PRELOAD a RCE

La investigación de Legit Security sobre Google Firebase y Apache mostró que escribir entradas no confiables en $GITHUB_ENV permite a un atacante establecer variables arbitrarias de entorno como LD_PRELOAD y NODE_OPTIONS, logrando la ejecución de código en flujos de trabajo privilegiados.

Nuestro github-env-injection.diff reproduce esta técnica con tres cargas útiles distintas, incluyendo LD_PRELOAD apuntando a un objeto compartido malicioso, NODE_OPTIONS con una inyección requerida y manipulación deGITHUB_PATH dólares. Las señales de github_env_write, ld_preloady github_path_write se activan como se esperaba.

Entrevista contagiosa: configuración del IDE como acceso inicial

La campaña Entrevistas Contagiosas , atribuida a la RPDC, se dirige a los desarrolladores mediante entrevistas de trabajo falsas, distribuyendo repositorios con archivos de .vscode/tasks.json que se ejecutan automáticamente al abrir carpetas. La presentación está oculta (reveal: never, echo: false), y la carga útil emplea curl | node para la ejecución silenciosa.

Nuestro ide-config-poisoning.diff captura toda la cadena de ataques, incluyendo el disparador de auto-ejecución (runOn: folderOpen), la presentación oculta, la carga útil de curl | node , la entrada de files.exclude que oculta el directorio .vscode y un gancho de postinstalación trojanizado con URLs codificadas en base64 y eval() para la ejecución de código. Seis señales captan esto a la vez.

Recomendaciones defensivas

Más allá de desplegar el detector, aquí hay algunas medidas de endurecimiento que surgieron directamente de los patrones de ataque que estudiamos:

  • Fija todas las acciones a SHA, no etiquetas, ni ramas. Las referencias fijadas por SHA evitan ataques retroactivos de modificación de etiquetas como tj-actions (CVE-2025-30066).
  • Secretos de alcance para pasos individuales en lugar de usar variables de entorno a nivel de trabajo. Cada paso solo debería tener acceso a los secretos que realmente necesita.
  • Emplea fichas efímeras y de corta duración cuando sea posible para reducir la superficie de ataque
  • Evita pull_request_target salvo que sea estrictamente necesario. Si tienes que usarla, nunca revises el código de la cabeza de PR en el mismo flujo de trabajo. Emplea un workflow_run-triggered workflow separado para operaciones que requieran tanto secretos como contexto de PR.
  • Establece licencias explícitas en cada flujo de trabajo porque las licencias predeterminadas de los tokens son demasiado amplios. Establece permissions: {} a nivel de flujo de trabajo y agrega licencias específicas por trabajo.
  • Activa persist-credentials: false al finalizar ya que el comportamiento predeterminado de acciones/checkout persiste en el GITHUB_TOKEN en el directorio de .git . Si subes artefactos, este token va con ellos.

Resumen

Las tuberías CI/CD se convirtieron en una superficie de ataque importante para el compromiso de la cadena de suministro. La misma automatización que hace posible la entrega moderna de software es la que los atacantes explotan para obtener credenciales, envenenar paquetes y cambiar a infraestructura en la nube. La revisión de código tradicional no capta bien estos patrones porque son sutiles, específicos de la plataforma y diseñados para parecer cambios legítimos de DevOps.

Combinar la extracción de señales basada en regex con el razonamiento LLM nos permite mostrar estos patrones en la fase de pull request, antes de que lleguen a producción. El repositorio incluye el modelo completo de amenazas, el conjunto de pruebas y diferenciales de ejemplo si quieres profundizar en los detalles o adaptarlo a tu propio entorno.

Para empezar, consulta el repositorio cicd-abuse-detector para instrucciones de configuración, el modelo completo de amenazas y diferenciales de ejemplo. Siempre nos interesa conocer nuevos patrones de ataque e ideas de detección. Chatea con nosotros en nuestra comunidad Slack y haz preguntas en nuestros foros de discusión.

Abuso de CI/CD a través de MITRE ATT&CK

Empleamos el marco MITRE ATT&CK para mapear las tácticas, técnicas y procedimientos que los adversarios emplean contra las canalizaciones CI/CD.

Táctica

TácticaRelevancia CI/CD
Acceso a credenciales (TA0006)Recolectando secretos de entornos CI
Ejecución (TA0002)Ejecución de comandos en pipeline runners
Persistencia (TA0003)Disparadores programados, flujos de trabajo basados en crons
Evasión de Defensa (TA0005)Manipulación de marca de tiempo de compromiso, evasión de enmascaramiento de registro
Acceso inicial (TA0001)Credenciales de desarrollador comprometidas, phishing por PATs
Movimiento lateral (TA0008)Uso de credenciales de la nube recolectadas para pivotar

Técnicas

TécnicaAplicación CI/CD
T1552: Credenciales no aseguradasSecretos expuestos en variables de entorno CI, artefactos y memoria del runner
T1195.002: Cadena de suministro de software de compromisoAcciones, dependencias y archivos de bloqueo envenenados
T1059: Intérprete de comandos y secuencias de comandoscurl
T1070.006: TimestompFechas de commit retroactivas para evitar la revisión
T1098: Manipulación de cuentasEscalada de licencias mediante write-all, id-token: write
T1078: Cuentas válidasPATs robados por desarrolladores usados para modificar flujos de trabajo

Referencias

A lo largo de la investigación anterior se hizo referencia a lo siguiente:

Acerca de Elastic Security Labs

Elastic Security Labs es la rama de inteligencia de amenazas de Elastic Security dedicada a crear cambios positivos en el panorama de amenazas. Elastic Security Labs proporciona investigación disponible públicamente sobre amenazas emergentes con un análisis de los objetivos estratégicos, operativos y tácticos del adversario, y luego integra esa investigación con las capacidades de detección y respuesta integradas de Elastic Security.

Sigue a Elastic Security Labs en Twitter @elasticseclabs y echa un vistazo a nuestra investigación en www.elastic.co/security-labs/.