Lorsque je prépare un déploiement Python, une de mes préoccupations majeures est toujours la chaîne d’approvisionnement des dépendances. Une dépendance compromise — qu’il s’agisse d’une typosquatting, d’une mise à jour malveillante ou d’une backdoor volontaire — peut compromettre toute l’infrastructure. Dans cet article, je vous partage ma méthode concrète pour détecter une backdoor dans une dépendance pip avant de la pousser en production : outils, commandes et bonnes pratiques que j’utilise au quotidien.

Préparer un environnement sûr pour l’analyse

Avant de toucher au code suspect, j’isole l’analyse. J’utilise toujours un virtualenv ou un conteneur Docker pour éviter toute exécution accidentelle sur ma machine principale.

Commandes utiles :

  • Créer un virtualenv : python -m venv .venv_backdoor
  • Activer : source .venv_backdoor/bin/activate
  • Installer dans un dossier isolé (sans dépendances) : pip download nom_paquet && pip install --no-deps --target=./pkg nom_paquet.whl
  • 1) Récupérer la distribution et ses métadonnées

    La première étape consiste à récupérer l’archive (wheel ou sdist) et à inspecter les métadonnées :

  • Télécharger la distribution : pip download package==version
  • Extraire une sdist : tar -xzf package-version.tar.gz
  • Extraire un wheel : unzip package-version-py3-none-any.whl -d extracted_pkg
  • Vérifiez les fichiers clé : setup.py, pyproject.toml, PKG-INFO, et tous les scripts dans le package. Une backdoor peut être cachée dans des scripts d’installation ou dans un import exécutant du code à l’importation.

    2) Rechercher du code exécuté à l’import (import-time execution)

    Je scrute les fichiers __init__.py et tout module susceptible d’être importé automatiquement. Recherchez :

  • Appels à os.system, subprocess, socket, urllib, requests sans validation
  • Import de modules obscurs, obfuscation (base64, exec, compile)
  • Usage de eval/exec ou d’import dynamique
  • Exemples de commandes :

  • Recherche rapide : grep -RInE "exec|eval|os.system|subprocess|socket|requests|getattr|compile" extracted_pkg/
  • Détecter base64/obfuscation : grep -RInE "base64|binascii|marshal|zlib" extracted_pkg/
  • 3) Analyse statique avec des outils dédiés

    J’utilise plusieurs outils complémentaires — aucun n’est parfait, mais combinés ils couvrent beaucoup de cas.

    OutilUsage cléCommande
    pip-audit Vulnérabilités connues pip-audit -r requirements.txt
    bandit Analyse statique de code Python bandit -r extracted_pkg/
    safety Vulnérabilités SCA safety check -r requirements.txt
    trivy Scan d’images et packages trivy fs extracted_pkg/
    yara Règles pour patterns malveillants yara rules.yar extracted_pkg/

    Je lance ces outils et j’analyse les faux positifs. Bandit est très utile pour repérer les patterns risqués (eval, subprocess) ; pip-audit/safety repèrent les vulnérabilités connues. Trivy peut attraper des fichiers binaires suspects.

    4) Inspecter les scripts d’installation et entry points

    Les scripts fournis (console_scripts, scripts dans setup.py) sont des vecteurs classiques :

  • Vérifier setup.py / entry_points dans PKG-INFO
  • Ouvrir et lire chaque script installé pour s’assurer qu’il n’appelle pas un code externe dangereux
  • Commande :

  • Afficher entry points : python -c "import pkgutil, pkginfo; print(open('PKG-INFO').read())" (ou simplement lire PKG-INFO)
  • 5) Vérifier la chaîne de publication sur PyPI

    Je consulte l’historique du paquet sur PyPI : date des versions, auteurs, et propriétaires du projet. Un changement soudain de mainteneurs ou une version très récente sans historique sont des signaux d’alerte.

  • Aller sur https://pypi.org/project/package/
  • Regarder "Requires" et "Maintainers", lire la description et le changelog
  • Vous pouvez aussi utiliser l’API JSON :

  • Récupérer métadonnées : curl -s https://pypi.org/pypi/package/json | jq .
  • 6) Comparer le code avec les dépôts sources

    Souvent le package PyPI contient un côté compilé ou du code différent du repo GitHub. J’extrais la version installée et je la compare au dépôt source :

  • Cloner le repo officiel : git clone https://github.com/maintainer/repo.git
  • Comparer : diff -ruN repo/ extracted_pkg/
  • Une divergence surprenante peut indiquer que la version publiée contient du code malveillant non présent dans le repo source.

    7) Analyse dynamique (sandboxed)

    Si la statique indique des éléments suspects mais pas concluants, je fais tourner le package dans un environnement sandbox (Docker, VM) avec monitoring réseau/fichiers :

  • Créer un conteneur : docker run -it --rm --name scan python:3.11 /bin/bash
  • Installer : pip install --no-deps /path/to/package.whl
  • Monitoring : strace -f -e trace=network,process -o trace.log python -c "import package"
  • Surveiller le réseau : tcpdump -w capture.pcap
  • Je m’attends à voir des connexions réseau non justifiées, lancement de shells, connexion à des domaines obscurs, ou écritures dans /etc, /var, ~/.ssh.

    8) Signatures et hachages

    Vérifier les signatures GPG si disponibles et comparer les hachages. Un paquet signé par une clé connue est plus rassurant.

  • Vérifier hash : sha256sum package.whl
  • Comparer à la valeur publiée sur PyPI (files -> hash)
  • 9) Bonnes pratiques pour se protéger

  • Locker les versions dans requirements.txt avec hash (pip hash / pip-compile) et utiliser pip install --require-hashes
  • Utiliser des outils SCA dans CI (pip-audit, safety, trivy)
  • Limiter les droits : exécuter les services avec des comptes non-root
  • Utiliser des miroirs privés ou des proxy PyPI (Artifactory, Nexus) pour contrôler les packages autorisés
  • Établir une procédure manuelle de revue pour les nouvelles dépendances critiques
  • Outils et commandes récapitulatives que j’utilise systématiquement

  • pip download pkg==version
  • unzip / tar -xzf / grep -RInE pour repères rapides
  • bandit -r extracted_pkg/
  • pip-audit -r requirements.txt
  • safety check -r requirements.txt
  • trivy fs extracted_pkg/
  • yara rules.yar extracted_pkg/
  • diff -ruN repo/ extracted_pkg/
  • strace / tcpdump pour analyse runtime
  • En appliquant cette démarche, j’ai déjà repéré plusieurs packages contenant des appels réseau suspects ou des imports exécutant du code à l’importation. Aucun outil ne remplace la prudence humaine : croiser les résultats, vérifier l’historique du mainteneur et exécuter des tests en sandbox sont indispensables. Si vous voulez, je peux partager un checklist prête à intégrer en pipeline CI pour automatiser une grande partie de ces vérifications.