Vendredi 22 mai 2026, vers 18h UTC, un attaquant républie sous les tags historiques de quatre paquets très populaires de l'écosystème laravel-lang (laravel-lang/lang, laravel-lang/http-statuses, laravel-lang/attributes, laravel-lang/actions) ~700 versions malveillantes. Samedi 23 mai en début de journée, The Hacker News et Bleeping Computer publient les premières analyses. Packagist retire les versions concernées en fin de matinée. Au total, la fenêtre d'exposition active dure environ 36 heures, et touche tout projet PHP qui a lancé composer update ou composer install sans composer.lock verrouillé pendant cette période.
Le mécanisme d'attaque est élégant et dangereux. L'attaquant exploite le fait que GitHub permet aux tags d'un dépôt de pointer sur des commits situés dans un fork. Il forke laravel-lang, ajoute un commit malveillant dans son fork, puis réécrit les tags v1.x.y du dépôt original pour qu'ils pointent sur son commit. Composer télécharge alors le tarball du tag par hash sans vérifier qui en est le propriétaire ni d'où il vient. Un fichier helpers.php est injecté dans le paquet via la clé autoload.files du composer.json. À chaque exécution PHP qui inclut l'autoload Composer, le helpers.php est chargé, télécharge un stealer cross-platform depuis flipboxstudio[.]info et exfiltre une liste impressionnante de secrets.
Entre samedi soir et lundi midi, j'ai passé 9 heures à auditer 4 agences PHP françaises clientes ou amies (de 6 à 38 développeurs). 3 sur 4 utilisaient au moins un paquet laravel-lang en dépendance directe ou transitive. 2 sur 4 avaient des secrets cloud exposés sur des runners CI publics. Voici l'audit éclair que je leur ai imposé, et les 5 actions opérationnelles à appliquer si vous êtes développeur PHP en France.
L'audit éclair en 9 heures : la séquence appliquée sur 4 agences PHP françaises
Samedi 23 mai à 21h, j'ai démarré sur l'agence A (12 développeurs, ~28 projets Laravel actifs). Voici la séquence reproductible que j'ai itérée ensuite sur les agences B, C, D.
Heure 0 à 1 : inventaire. Cloner tous les repos de l'agence, lancer un script bash qui parse les composer.json et composer.lock et liste les projets qui ont laravel-lang/* en dépendance directe ou transitive. Sur l'agence A : 19 projets sur 28 utilisaient au moins une lib laravel-lang. L'exposition réelle dépend ensuite de la date de dernière exécution de composer install sur le runner CI.
# Script d'inventaire rapide
for repo in $(ls -d agency-repos/*/); do
echo "=== $repo ==="
cd "$repo"
composer show --installed 2>/dev/null | grep -i "laravel-lang"
cd ../..
done > inventory-laravel-lang.txtHeure 1 à 3 : détection des compromissions. Sur chaque projet à risque, lancer une recherche du marker dropper et des modifications récentes :
# Recherche du marker flipboxstudio et helpers.php récents
grep -r "flipboxstudio" vendor/ 2>/dev/null
find vendor/laravel-lang -name "helpers.php" -newermt "2026-05-21"
# Vérifier les egress logs réseau du runner CI vers flipboxstudio.info
zgrep -i "flipboxstudio" /var/log/nginx/*.log /var/log/squid/*.logSur agence A, 2 projets sur 19 avaient le marker présent dans vendor/. Sur agence B, 0 projet (composer.lock verrouillé à fin avril). Sur agence C, 4 sur 11 projets compromis (CI en composer update hebdomadaire automatique). Sur agence D, 1 sur 8.
Heure 3 à 5 : analyse de l'exposition secrets sur runners CI. Lister tous les secrets configurés sur les pipelines GitHub Actions, GitLab CI, Bitbucket Pipelines. Croiser avec les projets compromis pour identifier les secrets effectivement exposés au stealer. Sur agence C, le runner CI shared avait accès à AWS keys, Vault token, et un token GitHub PAT à droits étendus. Tous compromis potentiellement.
Heure 5 à 7 : remédiation immédiate sur les projets compromis. Rollback du composer.lock à la version pré-22 mai, suppression manuelle du vendor/, réinstallation propre. Réécriture du composer.json avec des contraintes serrées (~1.2.3 au lieu de ^1.0). Suppression temporaire des dépendances laravel-lang/* le temps de la mise à jour Packagist.
Heure 7 à 9 : rotation des secrets. Toutes les clés cloud AWS/Azure/GCP des projets concernés ont été régénérées, les tokens GitHub PAT révoqués et réémis, le secret Vault associé au CI renouvelé. Notification clients sur les 2 projets ayant traité des données utilisateurs pendant la fenêtre d'exposition (RGPD article 33 à 34, notification CNIL dans les 72h si risque significatif).
Action 1 : Pinning de versions strict dans composer.json
La défense la plus simple consiste à éviter les contraintes larges. Remplacer ^1.0 ou ~1.0 (qui acceptent toute version mineure ou patch supérieure) par une version exacte ou une plage très serrée sur les dépendances critiques.
{
"require": {
"laravel-lang/lang": "15.13.2", // pinning exact (le plus sûr)
"laravel-lang/http-statuses": "~3.5.1", // accepte 3.5.x seulement
"laravel-lang/attributes": "3.8.0" // pinning exact
}
}Trade-off : vous devez gérer les mises à jour à la main avec composer update laravel-lang/lang et revue de diff. C'est exactement le comportement qui vous protège : un attaquant qui republie un tag existant n'a aucun impact si votre composer.lock est verrouillé et que vous ne mettez pas à jour à l'aveugle.
Action 2 : Hash verification systématique via composer.lock
Le fichier composer.lock contient les hashes shasum de chaque tarball téléchargé. Quand vous lancez composer install avec un lock commité, Composer vérifie que le hash téléchargé correspond. Cela bloque la republication malveillante d'une version déjà installée.
Discipline à imposer en équipe : composer.lock commité dans tous les repos, composer install (et jamais update) dans la CI pour les builds de release, composer update uniquement en local par un développeur senior avec revue du diff avant commit du nouveau lock. Ajouter en CI :
# .github/workflows/ci.yml — extrait
- name: Install dependencies (locked)
run: composer install --no-dev --prefer-dist --no-progress --no-interaction
- name: Verify composer audit
run: composer audit --no-dev --format=jsonAction 3 : Désactiver l'autoload.files sur les libs de traduction
Le mécanisme exact qui rend l'attaque exécutable, c'est autoload.files dans le composer.json du paquet malveillant. Cette clé force PHP à require les fichiers listés à chaque exécution, indépendamment de leur utilisation. Pour une lib de traduction, ce comportement est absurde et inutile : on ne fait que charger des fichiers de langue à la demande.
La parade : configurer composer.json de votre projet pour refuser explicitement l'exécution de scripts sur les dépendances de traduction, ou installer en passant l'option --no-scripts sur les CI.
# Bloquer scripts au global
composer config --global allow-plugins.* false
# CI hardened
composer install --no-dev --no-scripts --no-plugins --prefer-distCe hardening casse certaines installations (paquets qui font de la post-install legit), donc à introduire progressivement avec un audit projet par projet. Pour les projets Laravel modernes, l'impact est faible.
Action 4 : Audit complet des dépendances PHP avec composer audit et Snyk
Depuis Composer 2.4 (2022), la commande composer audit interroge l'advisory database FriendsOfPHP et signale les vulnérabilités connues. Depuis le 23 mai 2026, les advisories laravel-lang ont été ajoutées. Lancer en local et en CI :
composer audit --no-dev --format=table
# Sortie attendue : alerte rouge sur toute version laravel-lang installée
# entre le 22 mai 18h UTC et le 23 mai 11h UTCCompléter avec Snyk Open Source ou GitHub Dependabot qui couvrent un périmètre plus large incluant les CVE custom et certaines threats supply chain non encore publiées sur FriendsOfPHP. Pour les retours terrain sur l'automatisation Dependabot et Trivy en environnement PME, voir l'analyse Plug-Tech sur Project Glasswing et le SBOM dynamique.
Action 5 : Rotation immédiate de tous les secrets exposés à l'ensemble du build
Si votre CI a lancé composer install sur une dépendance laravel-lang entre le 22 mai 18h UTC et le 23 mai 11h UTC, vous devez considérer comme potentiellement compromis tous les secrets accessibles par le runner pendant ce build. La liste type pour un runner CI Laravel moderne :
- Clés AWS / Azure / GCP utilisées pour déploiement, S3, RDS, ECR.
- Tokens GitHub PAT, GitLab Personal Access Token, Bitbucket app password.
- Secrets Vault HashiCorp, secrets Kubernetes accessibles via kubeconfig embarqué.
- Mots de passe DB de staging et préprod si stockés en clair dans les env CI.
- Tokens API tiers (Stripe, Mailgun, Twilio, Sendgrid, Anthropic, OpenAI).
- Clés SSH déposées sur le runner pour des déploiements ssh.
- Cookies de session navigateur, si tests E2E avec Playwright/Cypress en CI.
La rotation prend typiquement 4 à 12 heures pour un projet Laravel moyen. Le coût d'une non-rotation, en revanche, peut atteindre des dizaines de milliers d'euros (vol cloud, exfiltration data, ransomware). C'est un investissement non négociable. Pour le pilotage opérationnel de cette rotation et l'audit de la posture SOC plus large, l'équipe WebGuard Agency propose un sous-traité standard que nous intégrons à nos missions cyber côté code.
Auditer votre flotte PHP contre la chaîne d'approvisionnement Composer
Notre audit d-open cartographie vos repos Laravel/Symfony, détecte les paquets compromis, automatise la rotation des secrets et durcit votre pipeline CI/CD. Livrable conforme NIS2.
Demander un audit ComposerNotre avis d'expert n°1 : pourquoi la vulnérabilité tag-rewrite n'est pas un bug Composer
Beaucoup de tweets accusent Composer ou Packagist. C'est partiellement injuste. La racine du problème est dans le modèle de confiance GitHub : un tag dans un dépôt peut pointer sur un commit qui n'est pas dans le dépôt mais dans un fork. Composer télécharge le tarball par hash référencé par le tag, sans pouvoir distinguer un commit upstream légitime d'un commit forké hostile.
La défense systémique passe par GitHub (verrouillage des tags sur l'ancestry du dépôt) ou par un schéma de signature des releases (Sigstore, in-toto). En attendant, la responsabilité est dans le pipeline développeur : pinning, lock, audit, hardening autoload. Cette attaque s'inscrit dans une lignée déjà longue (cPanel CVE-2026-41940, npm event-stream 2018, PyPI ctx 2022) qui montre que la supply chain logicielle est devenue la première surface d'attaque exploitée massivement.
Notre avis d'expert n°2 : le profil des agences PHP françaises les plus exposées
Sur les 4 agences auditées, le facteur de risque numéro un n'était pas la taille ni le niveau de séniorité technique. C'était la politique de mise à jour automatique des dépendances. Les agences qui lançaient un composer update automatique hebdomadaire dans la CI sans revue humaine étaient massivement compromises. Celles qui maintenaient un composer.lock verrouillé et ne mettaient à jour qu'avec revue manuelle (chaque trimestre par un dev senior) étaient totalement épargnées.
C'est contre-intuitif : la discipline ralentit mais protège. La vitesse d'adoption automatique est exactement ce qui ouvre la porte aux attaques supply chain. Le bon compromis est probablement un mix : Dependabot ou Renovate avec règle de seul auto-merge sur les patches sécurité explicitement avis, jamais sur les versions mineures sans revue.
Mettre en place une chaîne CI/CD PHP hardened contre les attaques supply chain
Sprint d-open de 2 semaines : composer.lock policy, audit FriendsOfPHP en CI, hardening autoload, rotation secrets automatisée, runbook NIS2. Formation équipe incluse.
Lancer le sprint hardeningFAQ : Laravel-Lang supply chain 22-23 mai 2026
Que s'est-il passé sur Laravel-Lang les 22 et 23 mai 2026 ?
Un attaquant a republié environ 700 versions malveillantes sous des tags historiques sur 4 paquets Composer de l'écosystème laravel-lang. Il a exploité le fait que GitHub permet aux tags de pointer sur des commits dans un fork. Composer télécharge le tag par hash sans vérification de propriété. Un fichier helpers.php injecté via autoload.files télécharge un stealer cross-platform depuis flipboxstudio.info qui exfiltre clés cloud, secrets Kubernetes/Vault, tokens CI/CD, SSH, fichiers env, navigateurs, password managers, wallets crypto. Packagist a retiré les versions le 23 mai.
Comment vérifier si mon projet PHP français est compromis ?
Quatre commandes à lancer. Un, grep -r flipboxstudio vendor/ pour repérer l'URL du dropper. Deux, composer show laravel-lang/* pour lister les versions installées et croiser avec les advisories Packagist publiées le 23 mai. Trois, find vendor/laravel-lang -name helpers.php -newer /tmp/cutoff avec cutoff calé sur le 21 mai. Quatre, vérifier les connexions sortantes du conteneur ou serveur vers flipboxstudio.info dans les logs réseau ou egress firewall.
Quelles sont les 5 actions à appliquer en priorité ?
Pinning de versions strict, hash verification via composer.lock, désactivation de l'autoload.files sur les libs de traduction, audit avec composer audit et Snyk, rotation immédiate de tous les secrets CI/CD accessibles depuis le runner.
Le pinning de versions et le composer.lock suffisent-ils à se protéger ?
Le composer.lock protège efficacement contre la republication d'une même version avec un nouveau contenu. Mais le risque existe si vous lancez composer update sans relire le diff, ou si vous utilisez des contraintes larges. La défense complète combine quatre couches : composer.lock commité, contraintes serrées, composer audit en CI, et désactivation de l'autoload sur les paquets qui n'en ont pas besoin techniquement.