Saltar al contenido
Volver al Blog

TeamPCP Cascade: cuando tu herramienta de seguridad es la puerta trasera

DevSecOps Space 3 min de lectura

El 27 de febrero de 2026, un bot llamado hackerbot-claw abrió un Pull Request contra el repositorio de Trivy, el escáner de seguridad open source más usado en pipelines de CI/CD. El PR estuvo abierto dos minutos. Un maintainer lo rechazó y lo cerró sin escalar.

Dieciocho días después, TeamPCP lanzó un ataque coordinado en tres vectores que comprometió ~500.000 pipelines, envenenó 82 tags de GitHub Actions y terminó backdooreando LiteLLM: el proxy que centraliza todas las API keys de IA de una organización.

El patrón que nadie detuvo

El PR aprovechó un workflow con pull_request_target — una configuración documentada como peligrosa desde 2021 (el patrón “Pwn Request”). Eso ejecutó código del fork con acceso al GITHUB_TOKEN del repo base. En minutos, las credenciales estaban exfiltradas.

La respuesta de Aqua Security rotó credenciales de forma no-atómica — en días, no en un bloque sincronizado. Durante ese intervalo, TeamPCP generó tokens de reemplazo con el service account todavía válido. Acceso residual: 18 días.

El 19 de marzo usaron ese acceso para:

  • Force-push de 75 tags de trivy-action + 7 de setup-trivy en 17 minutos
  • Scraping de memoria del proceso Runner.Worker en cada pipeline víctima
  • Recuperación de GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY, PYPI_API_TOKEN, NPM_TOKEN y más

Los secrets marcados como *** en los logs de Actions no están protegidos: el masking es solo un filtro de display. El secreto vive en plaintext en la memoria del runner, y cualquier código ejecutándose en el mismo proceso puede leerlo.

El giro: LiteLLM como vault de credenciales de IA

Con tokens de PyPI recuperados de los pipelines comprometidos, TeamPCP publicó LiteLLM 1.82.7 y 1.82.8 en PyPI el 24 de marzo. Ventana de exposición: 46 minutos a 95 millones de descargas mensuales.

El código malicioso nunca estuvo en el repositorio de GitHub de LiteLLM. La inyección ocurrió post-build, dentro del wheel, antes del upload a PyPI. pip no detectó nada porque verifica consistencia interna del paquete, no fidelidad con el source.

La versión 1.82.8 agregó litellm_init.pth: un archivo .pth de Python que ejecuta el payload de exfiltración de credenciales en cada invocación de Python del sistema — sin importar LiteLLM, sin acción del usuario.

LiteLLM no es solo un paquete más comprometido. Es el vault de credenciales de IA: un proxy que, en producción, tiene acceso a cada request, cada response y cada system prompt que pasa por él hacia OpenAI, Anthropic, Bedrock y el resto. Un proxy comprometido puede loggear, modificar y redirigir todo eso, indefinidamente, hasta que el equipo actualice la versión.

Lo que tenés que llevarte

  1. pull_request_target con código de forks = vector de entrada. Auditá tus workflows. Si un workflow en el contexto base ejecuta código de un fork, cualquiera puede abrir un PR y correr código con tus secrets.

  2. La rotación de credenciales debe ser atómica. Si un atacante tiene sesiones activas, una rotación escalonada le da tiempo para renovar tokens antes de que expiren.

  3. Pinear por digest, no por tag. Los tags son mutables — pueden apuntar a contenido diferente en cualquier momento. aquasec/trivy@sha256:... es inmutable.

  4. Los AI gateways son una nueva categoría de target. La blast radius de comprometer un proxy de IA no escala con el tamaño de una organización: escala con todas las organizaciones que lo usan simultáneamente.


📖 Fuente original: Análisis forense completo en Part I: Twenty Days of Silent Access y Part II: Backdooring the AI Credentials Vault — por Daniel Malvaceda en pipebreach.com.