D-OPEN

Attaque chaîne d'approvisionnement Laravel-Lang du 22-23 mai 2026 : 700 versions backdoorées, voici l'audit en 9 heures qui a sauvé 4 agences PHP françaises

Laravel-Lang supply chain 700 versions backdoorées mai 2026
Julien Moreau

Julien Moreau

Développeur senior et contributeur open source · 25 mai 2026 · 13 min de lecture

TL;DR

  • • Les 22 et 23 mai 2026, un attaquant republie ~700 versions malveillantes sous tags historiques sur 4 paquets Composer laravel-lang (lang, http-statuses, attributes, actions).
  • • Vecteur : tag-rewrite GitHub via fork. Un helpers.php injecté via autoload.files télécharge un stealer cross-platform depuis flipboxstudio.info.
  • Exfiltration : clés cloud AWS/Azure/GCP, secrets Kubernetes/Vault, tokens CI/CD, clés SSH, fichiers .env, navigateurs, password managers, wallets crypto.
  • 5 actions opérationnelles : pinning, hash verification composer.lock, désactiver autoload.files sur libs traduites, audit composer, rotation secrets CI/CD. Sources : thehackernews.com, bleepingcomputer.com.

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.

CHAÎNE D'EXPLOITATION LARAVEL-LANG 22-23 MAI 2026Fork GitHubcommit malveillantTag-rewrite~700 versionscomposer installautoload.files exechelpers.phpdropperflipboxstudio[.]info → stealer cross-platformExfiltration : AWS/Azure/GCP · Kubernetes · Vault · tokens CI/CDClés SSH · .env · navigateurs · password managers · wallets cryptoFenêtre d'exposition : ~36h · Packagist retrait le 23 mai 2026Sources : thehackernews.com et bleepingcomputer.com (23 mai 2026)

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.txt

Heure 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/*.log

Sur 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=json

Action 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-dist

Ce 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 UTC

Complé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 Composer

Notre 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.

TIMELINE LARAVEL-LANG SUPPLY CHAIN MAI 202622 mai 18hTag-rewrite700 versions23 mai 02h1ers signalementsTwitter / Reddit23 mai 09hThe Hacker NewsBleeping Computer23 mai 11hPackagist retireversionsFenêtre d'exposition active : ~17 heures (versions accessibles via Packagist)Effets persistants sur runners CI qui ont installé pendant la fenêtre

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 hardening

FAQ : 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.