Dépendance Composer ou npm compromise : le site n'a « rien touché »
Le site n'a « rien touché » : un paquet malveillant dans `vendor` ou `node_modules` suffit. Relisez les lockfiles, comparez aux empreintes connues. Réinstaller « pour être sûr » depuis le même cache ramène le même mal. Ce n'est pas un plugin WordPress oublié ; c'est une chaîne d'approvisionnement.
Un paquet malveillant dans vendor ou node_modules. Relisez lockfiles, comparez aux hashes connus. Réinstaller « pour être sûr » depuis le même cache ramène le même mal.
Le site n'a rien installé — quelqu'un l'a fait pour lui
Un développeur a lancé `composer update` un mardi. Un paquet a été usurpé, typo-squatté, ou un mainteneur a poussé une version hostile. Le code métier est propre. `vendor` ne l'est pas. Le symptôme ressemble à n'importe quel piratage : spam, minage, exfiltration, backdoor. L'entrée n'est pas `wp-login`.
Ça arrive aussi sans « update » : un `composer install` sur un lockfile déjà compromis, un zip de projet copié d'une clé USB, un cache CI. Dire « on n'a pas touché au site » est vrai côté pages. Faux côté arbre de dépendances.
On ne publie pas de liste d'exploits ni de noms de paquets à reproduire. On dit comment constater et se sortir, sans remettre le même mal.
Composer : lockfile, vendor, cache
`composer.lock` est la source de vérité de ce qui devrait être là. Comparez-le à un lockfile sain (Git d'avant l'incident, packagist / hash publiés). Un `composer.json` modifié (dépôt VCS inconnu, version `dev-master` soudain) est un signal.
`vendor` se régénère. S'il a été modifié à la main (un fichier PHP isolé dans un paquet), un `composer install` propre depuis un lock sain l'écrase — à condition de ne pas réutiliser un cache local qui contient encore l'archive malveillante. Videz le cache Composer de la machine et du CI.
Drupal, Laravel, Symfony : le métier est dans `app/` ou `web/modules/custom` ; la plaie peut être uniquement dans `vendor`. Drupal, site PHP.
- Lockfile vs Git d'avant les dates suspectes.
- Pas de dépôt Composer inconnu ajouté.
- Cache vidé (local + CI) avant réinstall.
npm / yarn / pnpm : la même logique, d'autres dossiers
`package-lock.json` / `yarn.lock` / `pnpm-lock.yaml`. `node_modules` en production (si vous le déployez) ou le bundle compilé (`dist`, `public/build`) qui a intégré le JS malveillant. Un front « statique » peut servir un mineur navigateur sans que PHP ait bougé. Cryptominage navigateur.
Les scripts `postinstall` sont le levier classique des paquets hostiles. Après incident, relisez ce qui s'exécute à l'install. Ne relancez pas `npm install` à l'aveugle sur le serveur de prod « pour réparer ».
Un CDN de paquets (jsDelivr, unmiroir interne) est un autre sujet si vous chargez hors lockfile. Script tiers / CDN.
Ce qu'un scan CMS ne verra pas
Wordfence ne parcourt pas forcément tout `vendor` comme le cœur. Un scan distant ne voit pas le PHP de CLI. Les signatures ratent un paquet écrit pour cette vague. Dates + lockfile + hash > « 0 alerte ».
Un plugin « security » installé après coup n'audit pas `composer.lock`. Ne le prenez pas comme preuve pour l'hébergeur. WAF vs plugin.
Journaux : un process node ou php inhabituel, des connexions sortantes. Demandez-les. Logs hébergeur.
Ne pas réinstaller depuis le tiroir empoisonné
Même lockfile + même cache = même archive. Purgez `~/.composer/cache`, caches CI, artefact Docker. Réinstallez depuis les registres officiels, versions épinglées du lock sain. Si le registre lui-même a servi une version hostile, descendez à une version antérieure connue, épinglée, documentée.
Un `vendor` commité dans Git : comparez le diff. Parfois plus clair qu'un lock. Ne commitez plus `vendor` ensuite si vous pouvez l'éviter — ou acceptez d'auditer chaque diff.
Image Docker « pour être sûr » construite sur le même cache : même piège. Docker WordPress — le principe s'étend.
CI, clés, et le poste du développeur
Le paquet a pu voler des secrets au moment de l'install (env CI, `.env` copié). Tournez tokens Packagist, npm, Git, cloud, SMTP. `.env` exposé.
Le poste du développeur : antivirus, secrets locaux, historique npm. Un incident supply chain n'est pas seulement « le serveur ». Changez le mot de passe panel quand même : un secret volé ouvre le reste.
alwaysdata / VPS : SSH, vous pouvez hasher et comparer. alwaysdata, VPS.
Après : versions épinglées, moins de paquets
Lockfiles commités, maj conscientes (pas `update` global le vendredi soir), moins de dépendances « au cas où ». C'est le moindre privilège appliqué aux paquets.
Surveillance trente jours : process, `site:`, dates dans vendor si vous le commitez. Garantie 30 jours.
WAF : filet pour le bruit HTTP, pas pour un `postinstall`. WAF.
Lien avec un incident « classique »
Un paquet hostile pose parfois un PHP à la racine ou un cron. Vous retrouvez alors un incident classique, avec une cause amont inhabituelle. Traitez les deux couches. Le constat pour l'hébergeur mentionne le paquet et le chemin. Compte suspendu.
Ne payez pas de rançon si le paquet a chiffré. Rançongiciel.
Créer un espace si la chaîne CI + prod dépasse le bricolage du dimanche. Un `composer install` depuis le même cache n'est pas un nettoyage. C'est une réinfection proprement versionnée.
Le constat hébergeur nomme le paquet et les chemins hors vendor (cron, racine). Pas besoin du mot « supply chain ». Guide.
Lockfile sain : où le trouver vraiment
Git d'avant les dates suspectes, artefact CI d'un build connu, poste d'un second développeur qui n'a pas `update` ce mardi-là. Pas « le lockfile du serveur aujourd'hui ». Comparez les hashes. Un `composer.json` avec un dépôt VCS inconnu est un signal, même si le lock « a l'air normal ».
Purgez caches local, CI, Docker. Réinstallez depuis les registres officiels, versions épinglées. Si le registre a servi une version hostile, descendez à une version antérieure documentée. Tournez les secrets (Packagist, npm, Git, `.env`, panel). `.env`.
Drupal / Laravel : le métier est hors vendor ; la plaie peut être uniquement dedans. Drupal. Front : le mal est parfois dans `dist`. CDN JS. WordPress sans Composer n'est pas immunisé dès qu'un thème build npm. Créer un compte.