Ce qui se passe
Les analyseurs de sécurité Laravel que l'on connaît — Ward, Checkpoint — relisent le code, la configuration et les dépendances pour y trouver des problèmes. Laravel Scalpel, de Harry Agustiana, pose une autre question : des fichiers de l'application déployée ont-ils déjà été ajoutés, modifiés ou supprimés ?
composer require hryagstn/laravel-scalpel
php artisan vendor:publish --tag=scalpel-configPHP 8.2 ou supérieur, Laravel 10 à 13.
Les six analyseurs
scalpel:scan en exécute six par défaut. Cinq inspectent les fichiers
présents, le sixième compare à un instantané.
- Structurel — fichiers PHP exécutables là où il ne devrait pas y en avoir,
par défaut
public/etstorage/. Il reconnaît.phpmais aussi.phtml,.pht,.phar, et les doubles extensions du typeshell.php.jpg. Sont autorisés par défautpublic/index.php,public/vendor/, et les vues et caches compilés de Laravel. - Code obfusqué — motifs classiques de porte dérobée :
eval(base64_decode(...)), exécution de charge compressée, appels de fonction construits dynamiquement, évaluation directe de l'entrée d'une requête, longues chaînes encodées. .htaccess— mappages de handler et de type MIME autorisant l'exécution de Python, Perl ou CGI,Options +ExecCGI, réécritures vers des URL externes, et directives commeauto_prepend_file..user.ini— directives PHP par répertoire :auto_prepend_file,auto_append_file,include_path,disable_functions. Une seule ligne y suffit pour exécuter un fichier caché à chaque requête.- Environnement —
.envmanquant, vide, illisible, lisible par tous sous Unix, ou déposé souspublic/;APP_KEYvide ; écarts de clés avec.env.example;APP_DEBUG=truealors queAPP_ENVvautproduction. L'option--productionapplique ce contrôle quel que soitAPP_ENV. - Baseline Diff — comparaison avec l'instantané enregistré.
L'instantané, et ses conditions
php artisan scalpel:baseline
php artisan scalpel:diffscalpel:baseline enregistre pour chaque fichier son empreinte SHA-256, sa
taille et sa date de modification. À créer seulement quand l'application est
dans un état de confiance : tant qu'il n'existe pas, les commandes signalent
un constat MEDIUM qui réclame sa création. Après chaque déploiement, le projet
conseille php artisan optimize puis scalpel:baseline --force.
Deux réglages méritent attention. L'option --fast compare d'abord taille et
date avant de réutiliser l'ancienne empreinte : moins de calcul, mais un fichier
modifié à taille et date préservées passe alors entre les mailles. Et la
signature HMAC (SCALPEL_SIGNING_ENABLED, SCALPEL_SIGNING_KEY — une clé
dédiée, pas l'APP_KEY) doit être activée avant la création du premier
instantané ; scalpel:diff rejette alors en CRITICAL un instantané mal signé.
Le piège à connaître avant la CI
Testé sur Scalpel 1.9.0 dans une application Laravel 13.31 neuve, le scan par
défaut ne remonte rien. Mais après un php artisan optimize, les vues
compilées sous storage/framework/views ont produit 100 constats MEDIUM
de variables variables et 2 constats HIGH sur des accents graves.
L'analyseur structurel autorise ce répertoire, l'analyseur de code obfusqué en
lit quand même le contenu. Ajouter storage/framework/views à
content_scan_excluded_paths règle le problème, au prix des contrôles de contenu
sur toutes les vues compilées.
En intégration continue, les formats table, json, annotations GitHub Actions
et SARIF sont disponibles, et --fail-on fixe la gravité qui fait échouer
le job (défaut : HIGH). Le code de sortie 0 signifie scan terminé sans
constat, 1 au moins un constat au niveau demandé, 2 des constats en dessous
de ce niveau ou un scan incomplet — un répertoire illisible ne passe donc
pas pour un succès. Un événement ScanFinished permet enfin d'envoyer ses
propres alertes sans analyser la sortie de la commande.
À retenir
Scalpel tourne dans le même processus et avec les mêmes droits que l'application : quelqu'un capable de modifier le code peut aussi modifier le scanner. Le projet recommande donc un déclenchement externe, des répertoires de code en lecture seule, et l'envoi des résultats hors du serveur concerné. C'est un détecteur de traces, pas une protection.
Source : Laravel Scalpel Scans for Filesystem Intrusion Evidence, Laravel News, 17 septembre 2026.