gha-security-review

Examen de sécurité GitHub Actions pour les vulnérabilités d'exploitation de workflows. À utiliser lorsqu'on vous demande de « examiner GitHub Actions », « auditer les workflows », « vérifier la sécurité CI », « sécurité GHA », « examen de sécurité des workflows », ou d'examiner .github/workflows/ pour les demandes pwn, l'injection d'expressions, le vol de credentials et les attaques de la chaîne d'approvisionnement. Axé sur l'exploitation avec des scénarios PoC concrets.

npx skills add https://github.com/getsentry/skills --skill gha-security-review

<!-- Motifs d'attaque et exemples réels provenant de l'analyse de la campagne HackerBot Claw par StepSecurity (2025): https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation -->

Examen de sécurité GitHub Actions

Trouvez les vulnérabilités exploitables dans les workflows GitHub Actions. Chaque constatation DOIT inclure un scénario d'exploitation concret — si vous ne pouvez pas construire l'attaque, ne la signalez pas.

Cette compétence encode les motifs d'attaque provenant d'exploits réels de GitHub Actions — pas de la théorie générique CI/CD.

Portée

Examinez les workflows fournis (fichier, diff ou dépôt). Recherchez dans la base de code selon les besoins pour tracer les chemins d'attaque complets avant de signaler.

Fichiers à examiner

  • .github/workflows/*.yml — toutes les définitions de workflow
  • action.yml / action.yaml — actions composites dans le dépôt
  • .github/actions/*/action.yml — actions réutilisables locales
  • Fichiers de configuration chargés par les workflows : CLAUDE.md, AGENTS.md, Makefile, scripts shell sous .github/

Hors de la portée

  • Workflows dans d'autres dépôts (notez uniquement la dépendance)
  • Permissions d'installation de GitHub App (notez si pertinent)

Modèle de menace

Signalez uniquement les vulnérabilités exploitables par un attaquant externe — quelqu'un sans accès en écriture au dépôt. L'attaquant peut ouvrir des PR à partir de forks, créer des issues et publier des commentaires. Il ne peut pas pousser vers des branches, déclencher workflow_dispatch, ou déclencher des workflows manuels.

Ne signalez pas les vulnérabilités qui nécessitent un accès en écriture pour être exploitées :

  • Injection d'entrée workflow_dispatch — nécessite un accès en écriture pour déclencher
  • Injection d'expression dans les workflows push uniquement sur les branches protégées
  • Injection d'entrée workflow_call où tous les appelants sont internes
  • Secrets dans les workflows workflow_dispatch/schedule uniquement

Confiance

Signalez uniquement les constatations de confiance ÉLEVÉE et MOYENNE. Ne signalez pas les problèmes théoriques.

Confiance Critères Action
ÉLEVÉE Tracé le chemin d'attaque complet, confirmé exploitable Signaler avec scénario d'exploitation et correctif
MOYENNE Chemin d'attaque partiellement confirmé, lien incertain Signaler comme nécessite vérification
FAIBLE Théorique ou atténué ailleurs Ne pas signaler

Pour chaque constatation ÉLEVÉE, fournissez les cinq éléments :

  1. Point d'entrée — Comment l'attaquant entre-t-il ? (PR de fork, commentaire sur issue, nom de branche, etc.)
  2. Charge utile — Qu'est-ce que l'attaquant envoie ? (code/YAML/entrée réelle)
  3. Mécanisme d'exécution — Comment la charge utile s'exécute-t-elle ? (expansion d'expression, checkout + script, etc.)
  4. Impact — Qu'est-ce que l'attaquant obtient ? (vol de token, exécution de code, accès en écriture au dépôt)
  5. Esquisse PoC — Étapes concrètes qu'un attaquant suivrait

Si vous ne pouvez pas construire les cinq, signalez comme MOYENNE (nécessite vérification).


Étape 1 : Classifier les déclencheurs et charger les références

Pour chaque workflow, identifiez les déclencheurs et chargez la référence appropriée :

Déclencheur / Motif Charger une référence
pull_request_target references/pwn-request.md
issue_comment avec analyse de commande references/comment-triggered-commands.md
${{ }} dans les blocs run: references/expression-injection.md
PATs / clés de déploiement / identifiants élevés references/credential-escalation.md
Checkout du code PR + chargement de fichier de configuration references/ai-prompt-injection-via-ci.md
Actions tierces (en particulier non épinglées) references/supply-chain.md
Bloc permissions: ou utilisation de secrets references/permissions-and-secrets.md
Exécuteurs auto-hébergés, utilisation du cache/artefacts references/runner-infrastructure.md
Toute constatation confirmée references/real-world-attacks.md

Chargez les références de manière sélective — uniquement ce qui est pertinent pour les déclencheurs trouvés.

Étape 2 : Vérifier les classes de vulnérabilités

Vérification 1 : Pwn Request

Le workflow utilise-t-il pull_request_target ET extrait-il le code du fork ?

  • Recherchez actions/checkout avec ref: pointant vers la tête PR
  • Recherchez les actions locales (./.github/actions/) qui proviendraient du fork
  • Vérifiez si une étape run: exécute du code à partir de la PR extraite

Vérification 2 : Injection d'expression

Des expressions ${{ }} sont-elles utilisées à l'intérieur de blocs run: dans des workflows déclenchables de l'extérieur ?

  • Mappez chaque expression ${{ }} dans chaque étape run:
  • Confirmez que la valeur est contrôlée par l'attaquant (titre PR, nom de branche, corps du commentaire — pas les ID numériques, SHAs ou noms de dépôts)
  • Confirmez que l'expression est dans un bloc run:, pas dans if:, with:, ou env: au niveau du job

Vérification 3 : Exécution de commande non autorisée

Un workflow déclenché par issue_comment exécute-t-il des commandes sans autorisation ?

  • Y a-t-il une vérification author_association ?
  • N'importe quel utilisateur GitHub peut-il déclencher la commande ?
  • Le gestionnaire de commandes utilise-t-il également des expressions injectables ?

Vérification 4 : Escalade de identifiants

Les identifiants élevés (PATs, clés de déploiement) sont-ils accessibles au code non fiable ?

  • Quel est le rayon d'impact de chaque secret ?
  • Un workflow compromis pourrait-il voler des tokens de longue durée ?

Vérification 5 : Empoisonnement de fichier de configuration

Le workflow charge-t-il la configuration à partir de fichiers fournis par la PR ?

  • Instructions d'agent IA : CLAUDE.md, AGENTS.md, .cursorrules
  • Configuration de build : Makefile, scripts shell

Vérification 6 : Chaîne d'approvisionnement

Les actions tierces sont-elles correctement épinglées ?

Vérification 7 : Permissions et secrets

Les permissions du workflow sont-elles minimales ? Les secrets sont-ils correctement délimités ?

Vérification 8 : Infrastructure d'exécuteur

Les exécuteurs auto-hébergés, les caches ou les artefacts sont-ils utilisés de manière sécurisée ?

Motifs sûrs (ne pas signaler)

Avant de signaler, vérifiez que le motif est réellement sûr :

Motif Pourquoi sûr
pull_request_target SANS checkout du code du fork N'exécute jamais le code de l'attaquant
${{ github.event.pull_request.number }} dans run: Numérique uniquement — non injectable
${{ github.repository }} / github.repository_owner Le propriétaire du dépôt contrôle cela
${{ secrets.* }} Pas un vecteur d'injection d'expression
${{ }} dans les conditions if: Évalué par le runtime Actions, pas le shell
${{ }} dans les entrées with: Passé comme paramètres de chaîne, non évalué par le shell
Actions épinglées au SHA complet Référence immuable
Déclencheur pull_request (pas _target) S'exécute dans le contexte du fork avec un token en lecture seule
Toute expression dans workflow_dispatch/schedule/push vers les branches protégées Nécessite un accès en écriture — hors du modèle de menace

Distinction clé : ${{ }} est dangereux dans les blocs run: (expansion shell) mais sûr dans if:, with:, et env: au niveau du job/étape (évaluation du runtime Actions).

Étape 3 : Valider avant de signaler

Avant d'inclure une constatation, lisez le YAML du workflow réel et tracez le chemin d'attaque complet :

  1. Lisez le workflow complet — ne vous fiez pas à la sortie grep uniquement
  2. Tracez le déclencheur — confirmez l'événement et vérifiez les conditions if: qui contrôlent l'exécution
  3. Tracez l'expression/checkout — confirmez qu'elle est dans un bloc run: ou référence réellement le code du fork
  4. Confirmez le contrôle de l'attaquant — vérifiez que la valeur correspond à quelque chose défini par un attaquant externe
  5. Vérifiez les atténuations existantes — enveloppe de variable d'environnement, vérifications author_association, permissions restreintes, épinglage SHA

Si un lien est rompu, marquez MOYENNE (nécessite vérification) ou abandonnez la constatation.

Si aucune vérification n'a produit de constatation, signalez zéro constatation. N'inventez pas de problèmes.

Étape 4 : Signaler les constatations

## Examen de sécurité GitHub Actions

### Constatations

#### [GHA-001] [Titre] (Sévérité : Critique/Élevée/Moyenne)
- **Workflow**: `.github/workflows/release.yml:15`
- **Déclencheur**: `pull_request_target`
- **Confiance**: ÉLEVÉE — confirmée par traçage du chemin d'attaque
- **Scénario d'exploitation**:
  1. [Attaque étape par étape]
- **Impact**: [Ce que l'attaquant obtient]
- **Correctif**: [Code qui corrige le problème]

### Nécessite vérification
[Éléments de confiance MOYENNE avec explication de ce qu'il faut vérifier]

### Examinés et confirmés sûrs
[Workflows examinés et confirmés sûrs]

Si aucune constatation : « Aucune vulnérabilité exploitable identifiée. Tous les workflows examinés et confirmés sûrs. »