Je vais être franc. GitHub Actions, c’est génial. Ça déploie, ça teste, ça signe, ça publie. Et ça peut aussi devenir… un petit aspirateur à secrets si on laisse filer deux ou trois détails.
Le truc, c’est que beaucoup de fuites ne ressemblent pas à des « hacks » spectaculaires. C’est souvent bête. Un echo $TOKEN dans un job de debug. Un workflow déclenché sur pull_request_target sans garde fou. Un cache qui garde plus que prévu. Une action tierce non pinée qui change sous vos pieds.
Donc, ici, je te propose un audit rapide, pragmatique, que tu peux faire en moins d’une heure sur la plupart des repos. Objectif : repérer les points qui sentent la fuite, puis corriger sans tout casser.
Si tu veux, je pourrai ensuite en faire une checklist imprimable que je mettrai aussi sur Le Blog Tech Pro de Samyn-Antoy ABASSE (https://monblog-sa-abasse.blogspot.com), avec des commandes prêtes à copier.
Pourquoi GitHub Actions est un endroit « sensible »
Quelques faits simples :
- Les runners manipulent des environnements complets, avec accès réseau, disque, artefacts, caches.
- Les secrets GitHub sont injectés comme variables d’environnement, et ils peuvent se retrouver dans des logs, des fichiers, des outputs, des artefacts.
- Les workflows se déclenchent parfois sur du code externe (PRs fork). Donc quelqu’un d’autre peut influencer ce qui s’exécute.
- Les actions tierces, si tu les utilises au tag
@v1, peuvent changer. Oui, même si « ça a toujours marché ».
En gros, ton pipeline est un mini serveur CI. Et comme tout serveur, il faut l’auditer.
Image : vue d’ensemble d’un workflow typique
L’audit rapide en 10 minutes : le scan visuel qui attrape 80 % des problèmes
Ouvre .github/workflows/*.yml. Puis cherche, vraiment à l’ancienne.
1) Vérifie les déclencheurs « dangereux » ou mal compris
Points à surveiller :
pull_request_target
Très pratique… et très piégeux. Il s’exécute dans le contexte du repo cible, avec accès aux secrets, même si le code vient d’un fork. Si tu checkout le code de la PR et que tu exécutes des scripts, tu offres un terrain de jeu.workflow_run
Peut enchaîner des workflows et passer des artefacts. Bien, mais ça peut aussi être un chemin détourné si tu n’as pas de conditions strictes.issue_comment,repository_dispatch,workflow_dispatch
Ce sont des portes d’entrée. Parfois voulues. Souvent trop ouvertes.
À faire : note tous les workflows qui touchent à des secrets et qui se déclenchent sur des événements externes.
2) Cherche les patterns de fuite dans les steps
Les suspects classiques :
run: echo ${{ secrets.X }}(même pour « tester »)run: printenvouenv | sort- scripts qui font
set -xen bash (trace complète) - outils qui loggent par défaut les headers HTTP (et donc les tokens)
- upload d’artefacts trop large :
path: .oupath: build/sans filtrer
3) Vérifie les permissions du token GitHub
Depuis 2021+, GitHub Actions supporte permissions: au niveau workflow ou job.
Si tu vois rien, tu es souvent en mode trop permissif selon le contexte. Et quand tu vois permissions: write-all, c’est rarement justifié.
Image : illustration « secrets » et logs
Étape 1 : verrouiller le GITHUB_TOKEN (le vrai gain rapide)
Dans beaucoup de pipelines, le GITHUB_TOKEN a plus de droits que nécessaire. Et quand un job se fait détourner, c’est ce token qui sert à pousser du code, créer des releases, modifier des issues, exfiltrer des artefacts privés.
Recommandation simple
Dans la majorité des workflows CI (tests, lint, build), mets :
yaml permissions: contents: read
Et ensuite, tu ajoutes uniquement ce dont tu as besoin, au job près.
Exemple : un job qui publie un package GitHub, ok, tu montes :
yaml permissions: contents: read packages: write
Exemple : un job qui crée une release :
yaml permissions: contents: write
Oui, c’est un peu plus verbeux. Mais tu réduis la surface d’attaque, tout de suite.
Étape 2 : arrêter d’utiliser des actions non pinées (ou mal pinées)
Tu as déjà vu ça :
yaml
- uses: actions/checkout@v4
- uses: docker/build-push-action@v6
- uses: some-user/some-action@v1
Le problème n’est pas actions/checkout. Le problème, c’est surtout la troisième ligne. Un tag peut bouger. Un repo peut être compromis. Une release peut changer.
Bonne pratique
Pinner par SHA de commit, au moins pour les actions tierces sensibles.
Exemple :
yaml
- uses: some-user/some-action@a1b2c3d4e5f6g7h8i9j0
C’est moins joli. Mais c’est stable.
Astuce : tu peux garder un commentaire avec le tag pour t’y retrouver.
Étape 3 : attention aux PRs de forks (le piège classique)
Dans un repo open source ou juste public, c’est normal d’avoir des PRs de forks.
Règle d’or :
- Sur
pull_requestvenant d’un fork, GitHub ne fournit pas les secrets. - Sur
pull_request_target, GitHub peut fournir les secrets car il exécute dans le contexte du repo base.
Donc, si tu utilises pull_request_target, tu dois éviter d’exécuter le code de la PR sans validation.
Pattern plus sûr
- Job 1 : validation minimale, sans checkout du code PR, ou en lecture seule, sans secrets.
- Job 2 : si label « ok-to-test » ou si auteur membre, alors seulement tu fais des actions sensibles.
Exemple d’idée (simplifiée) :
yaml on: pull_request_target:
jobs: safe-check: permissions: contents: read runs-on: ubuntu-latest steps: - run: echo "Checks sans exécuter le code de la PR"
privileged: if: contains(github.event.pull_request.labels.*.name, 'ok-to-test') permissions: contents: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - run: ./scripts/ci-sensitive.sh
Ce n’est pas parfait. Mais c’est déjà une séparation claire entre « je regarde » et « j’exécute ».
Étape 4 : logs, masquage, et fausses sécurités
GitHub masque automatiquement certains secrets dans les logs, mais :
- le masquage a des limites (transformations, encodage, découpage)
- si tu réécris le secret (base64, URL encode, substring), il peut apparaître
- certains outils réémettent le secret en plusieurs morceaux
À faire tout de suite
- Ne jamais faire
printenvdans un job qui a des secrets. - Évite
set -xen bash sur des steps sensibles. - Utilise
::add-mask::pour masquer des valeurs dérivées.
Exemple :
bash echo "::add-mask::$DERIVED_TOKEN"
Et surtout : ne garde pas des « steps debug » dans le main. Même commentés. On les réactive un jour. On oublie. Et voilà.
Image : capture mentale « checklist »
Étape 5 : artefacts, caches, et le côté « je zippe tout »
Là aussi, c’est souvent involontaire.
Artefacts
Si tu fais :
yaml
- uses: actions/upload-artifact@v4 with: name: build path: .
Tu peux embarquer :
.env- fichiers de config avec tokens
.npmrcavec un auth token- logs d’outils
- dossiers cachés contenant des credentials temporaires
À faire : whitelist stricte des chemins.
Exemple :
yaml path: | dist/** coverage/**
Caches
Le cache peut garder des fichiers contenant des secrets (rare, mais possible selon les outils). Exemple : config de registry, credentials cloud déposés sur disque, ou répertoires d’outils.
À faire : cache uniquement des répertoires connus et « non secrets », typiquement dépendances.
Étape 6 : environnements GitHub et protections
Si tu déploies en prod, utilise les environments GitHub.
Avantages :
- secrets séparés par environnement
- reviewers obligatoires avant accès aux secrets
- règles de branche, délais, etc
Ça te donne un vrai bouton « pause » humain. Et quand tu as plusieurs personnes sur le repo, c’est juste sain.
Étape 7 : détecter les exfiltrations bêtes (et oui, ça arrive)
Quelques signaux faibles :
- un step qui fait des requêtes réseau vers un domaine inconnu
- utilisation de
curlavec headers d’auth dans un contexte non nécessaire - dépendances installées depuis des sources non verrouillées (scripts
postinstall) - scripts qui lisent
~/.sshou~/.aws
Petit audit grep utile
Dans le repo :
- chercher
secrets.dans les workflows - chercher
curletAuthorization - chercher
upload-artifact - chercher
pull_request_target
Tu peux même faire un mini rapport.
Bonus : un template minimal « plus safe » pour CI
yaml name: ci
on: push: branches: [ "main" ] pull_request:
permissions: contents: read
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - run: npm ci - run: npm test
Ce workflow ne touche pas aux secrets. Permissions minimales. C’est une base saine.
Ce que je ferais sur un repo réel, maintenant, sans attendre
- Mettre
permissions: contents: readpartout où possible. - Identifier les workflows qui manipulent des secrets. Les isoler.
- Vérifier tous les triggers, surtout
pull_request_target. - Pinner les actions tierces sensibles par SHA.
- Réduire artefacts et caches à une whitelist.
- Ajouter environments et approvals pour prod.
Et ensuite seulement, je m’amuserais avec du durcissement plus avancé (OIDC cloud, attestations, signature, provenance). Mais sans la base, ça ne sert à rien.
Mini conclusion (et petite suite logique)
Les fuites de secrets dans GitHub Actions, ce n’est pas une fatalité. C’est surtout un problème de défauts, de copier coller, et de « on verra plus tard ».
Si tu veux une suite, je peux publier sur https://monblog-sa-abasse.blogspot.com une version checklist, plus une section « cas concrets » : un workflow vulnérable, l’exploitation typique, puis la correction propre. Et oui, avec des exemples réalistes, pas juste des principes.
En attendant, ouvre tes workflows. Lis les triggers. Lis les permissions. Et traque les echo, les artefacts trop larges, et les actions non pinées. Ça suffit souvent à dormir mieux.
Questions fréquemment posées
Pourquoi GitHub Actions est-il considéré comme un environnement sensible ?
GitHub Actions manipule des environnements complets avec accès réseau, disque, artefacts et caches. Les secrets sont injectés comme variables d'environnement et peuvent se retrouver dans les logs ou fichiers. De plus, les workflows peuvent se déclencher sur du code externe, notamment via des pull requests forkées, ce qui peut permettre à des tiers d'influencer l'exécution. Enfin, les actions tierces non verrouillées peuvent changer sous vos pieds, rendant la sécurité critique.
Quels sont les déclencheurs de workflows GitHub Actions à surveiller pour éviter les fuites de secrets ?
Les déclencheurs à risque incluent : 'pull_request_target', qui s'exécute dans le contexte du dépôt cible avec accès aux secrets même si le code vient d'un fork ; 'workflow_run', qui peut enchaîner des workflows sans conditions strictes ; et des événements comme 'issue_comment', 'repository_dispatch' ou 'workflow_dispatch' qui peuvent ouvrir des portes d'entrée trop larges.
Quels patterns dans les étapes (steps) des workflows peuvent entraîner des fuites de secrets ?
Les patterns suspects comprennent l'utilisation de commandes comme 'echo ${{ secrets.X }}' en clair dans les jobs de debug, l'exécution de 'printenv' ou 'env | sort' qui exposent toutes les variables d'environnement, l'utilisation de scripts bash avec 'set -x' activé qui trace toutes les commandes, ainsi que le téléchargement d'artefacts trop larges sans filtrage précis.
Comment vérifier et configurer correctement les permissions du GITHUB_TOKEN pour renforcer la sécurité ?
Depuis 2021+, il est possible de définir les permissions au niveau workflow ou job via la clé 'permissions:'. Il est recommandé d'éviter les permissions trop larges comme 'write-all'. Par défaut, limiter à 'contents: read' suffit pour la plupart des jobs CI (tests, lint, build). Pour des jobs spécifiques (ex: publication), augmenter uniquement les permissions nécessaires comme 'packages: write' permet de réduire le risque en cas de détournement.
Pourquoi faut-il être prudent avec l'utilisation du déclencheur 'pull_request_target' ?
'pull_request_target' s'exécute dans le contexte du dépôt cible avec accès aux secrets même si le code provient d'un fork externe. Si vous exécutez le code de la PR sans précautions, cela peut offrir un terrain propice à l'extraction ou à l'exploitation des secrets présents dans vos workflows.
Quelles bonnes pratiques appliquer pour réaliser un audit rapide efficace sur GitHub Actions ?
Un audit rapide consiste à ouvrir tous les fichiers '.github/workflows/*.yml' et rechercher visuellement : 1) Les déclencheurs dangereux ('pull_request_target', etc.) ; 2) Les patterns suspects dans les steps (exposition directe des secrets, logs excessifs) ; 3) La configuration des permissions du token. Cette méthode permet d’identifier environ 80 % des problèmes courants en moins d’une heure sans outils complexes.
0 Commentaires