Le message à faire passer en entretien : la CI/CD est du Tier 0. Le runner qui déploie en production détient, de fait, les droits de production. Un attaquant n’a pas besoin d’exploiter ton application s’il peut modifier le pipeline qui la construit. Complète la fiche 10 (§4 DevSecOps) et la fiche 13 (supply chain).
Les 8 points d’entrée à savoir énumérer :
| # | Point d’entrée | Exemple concret |
|---|---|---|
| 1 | Le développeur | Poste compromis, token PAT volé, absence de MFA sur le SCM |
| 2 | Le code source | Commit malveillant, absence de revue, git push --force sur main |
| 3 | Les dépendances | Typosquatting, dependency confusion, mainteneur compromis (XZ Utils) |
| 4 | La définition du pipeline | Un attaquant modifie .gitlab-ci.yml / .github/workflows/* dans sa MR et son job s’exécute avec les secrets |
| 5 | Les actions/templates réutilisés | tj-actions/changed-files compromis en mars 2025 (CVE-2025-30066) : l’action modifiée dumpait les secrets dans les logs de build de milliers de dépôts |
| 6 | Le runner / l’agent de build | Runner auto-hébergé partagé, non éphémère, privileged: true, réutilisation du cache entre projets |
| 7 | Les artefacts & le registre | Image non signée, tag mutable (latest), registre en écriture ouverte |
| 8 | Le déploiement | Credentials cloud longue durée dans une variable CI, agent GitOps surprivilégié |
Cas d’école à citer : Codecov (2021, script bash CI altéré → exfiltration des variables d’environnement de milliers de pipelines), SolarWinds (build compromis), tj-actions (2025), PyPI/npm (paquets malveillants récurrents).
Vocabulaire à placer : Poisoned Pipeline Execution (PPE) — direct (le fichier de pipeline
est modifiable par l’attaquant), indirect (un fichier utilisé par le pipeline l’est : Makefile,
package.json scripts, Dockerfile, tests) — et dependency chain abuse.
Référentiel : OWASP Top 10 CI/CD Security Risks (CICD-SEC-1 à 10) et SLSA (fiche 20).
main protégée, push direct interdit (y compris pour les admins),
force-push interdit, suppression interdite, ≥ 1 revue approbatrice (2 sur les dépôts
critiques), rejet des approbations obsolètes au nouveau commit, revue obligatoire du
propriétaire du code (CODEOWNERS), résolution des conversations exigée.workflow_dispatch)..gitlab-ci.yml# ---------- CONTRE-EXEMPLE : tout ce qu'il ne faut pas faire ----------
image: docker:latest # tag mutable, image non pinnée
services:
- docker:dind # DinD => runner privileged => évasion possible
variables:
AWS_ACCESS_KEY_ID:"AKIA..." # secret en clair dans le repo
DOCKER_TLS_CERTDIR:"" # TLS désactivé sur le daemon Docker
include:
-project:'platform/ci-templates'
file:'/deploy.yml' # pas de `ref:` => on récupère la HEAD, non reproductible
deploy:
script:
- curl -s <https://get.example.com/install.sh> | bash # code distant non vérifié (Codecov)
- kubectl apply -f k8s/
# pas de `rules` => le job tourne sur toutes les branches, y compris une MR d'attaquant