Ein am 17. September 2026 veröffentlichter Beitrag von Laravel News stellt Laravel Scalpel vor. Das Paket stammt von Harry Agustiana und läuft innerhalb einer Laravel-Anwendung. Es sucht nach Dateisystem-Spuren eines möglichen Einbruchs, etwa eingeschleusten PHP-Dateien, verstecktem Code, veränderten Serverdirektiven und Änderungen nach dem Deployment.

terminal
php artisan scalpel:scan
php artisan scalpel:scan --only=structural,obfuscated
php artisan scalpel:scan --only=userini

Ward und Checkpoint verfolgen ein anderes Ziel. Sie prüfen Quellcode, Konfiguration und Abhängigkeiten auf Sicherheitsprobleme. Scalpel untersucht eine bereits ausgelieferte Anwendung auf Dateien, die hinzugefügt, geändert oder gelöscht wurden.

scalpel:scan startet standardmäßig sechs Scanner. Fünf davon prüfen den aktuellen Dateibestand, während Baseline Diff ihn mit einem gespeicherten Snapshot vergleicht. Der Structural Scanner untersucht public/ und storage/ auf ausführbare PHP-Dateien. Er erkennt .php, .phtml, .pht und .phar sowie doppelte Endungen wie shell.php.jpg. public/index.php, public/vendor/ sowie Laravels kompilierte Views und Caches sind zunächst erlaubt. Scan-Verzeichnisse und Allow-Listen lassen sich konfigurieren.

Der Obfuscated-Code-Scanner sucht unter anderem nach eval(base64_decode(...)), der Ausführung komprimierter Payloads, dynamischen Funktionsaufrufen, direkter Auswertung von Request-Daten und langen kodierten Zeichenketten. Einzelne Muster können in config/scalpel.php deaktiviert werden, wenn legitimer Anwendungscode einen Treffer erzeugt. Der .htaccess-Scanner meldet Handler- und MIME-Zuordnungen für Python, Perl, CGI und andere Interpreter. Zusätzlich prüft er Options +ExecCGI, Weiterleitungen zu externen URLs und Direktiven wie auto_prepend_file. Der .user.ini-Scanner erfasst auto_prepend_file, auto_append_file, include_path und disable_functions. Mit auto_prepend_file kann ein Angreifer bei jeder Anfrage eine versteckte Datei ausführen.

Die Umgebungsprüfung meldet fehlende, leere oder nicht lesbare .env-Dateien, .env-Dateien unter public/ und unter Unix-artigen Systemen auch weltweit lesbare Dateien. Ein leeres APP_KEY wird gemeldet. Außerdem vergleicht Scalpel die Schlüssel aus .env mit .env.example. Fehlende oder unerwartete Schlüssel gelten als mögliche Einbruchsspur. Bei APP_ENV=production wird APP_DEBUG=true beanstandet. --production aktiviert diese Prüfung unabhängig von APP_ENV und meldet zusätzlich APP_ENV=local.

Mit scalpel:scan und --only lassen sich Scanner auswählen. scalpel:baseline speichert für jede einbezogene Datei einen SHA-256-Hash, die Größe und die Änderungszeit. scalpel:diff meldet neue, geänderte und gelöschte Dateien. Eine Baseline sollte erst nach einem vertrauenswürdigen Bereitstellungsstand erstellt werden. Bis dahin liefern scalpel:scan und scalpel:diff einen MEDIUM-Treffer mit der Aufforderung, eine Baseline anzulegen. Nach einem Deployment empfiehlt das Projekt php artisan optimize und anschließend scalpel:baseline --force.

Die Standardausnahmen betreffen häufig wechselnde Pfade wie Logs, Sessions, kompilierte Views und storage/app. vendor/ bleibt bei Inhaltsprüfungen außen vor, wird aber in Baseline-Vergleiche einbezogen. Eine neu hinzugefügte Datei in einem installierten Paket erscheint dadurch im Diff. Im Strict-Modus wird bei jedem Vergleich jede Datei gehasht. --fast verwendet den alten Hash weiter, wenn Größe und Änderungszeit unverändert sind. Ein Angreifer kann eine Inhaltsänderung dadurch verbergen, wenn er beide Werte beibehält. Andere Scanner können die Datei weiterhin anhand ihres Inhalts oder Speicherorts finden.

Baselines und JSON-Berichte lassen sich per HMAC signieren. Dafür müssen SCALPEL_SIGNING_ENABLED aktiviert und SCALPEL_SIGNING_KEY mit einem eigenen Schlüssel belegt werden, der nicht APP_KEY entspricht. scalpel:diff prüft signierte Baselines und stuft eine fehlende oder ungültige Signatur als CRITICAL ein. Der Schutz greift nicht, wenn ein Angreifer den Schlüssel lesen oder den Scanner verändern kann. Die Signierung sollte vor der ersten Baseline aktiviert werden. scalpel:verify prüft einen gespeicherten JSON-Bericht.

Der Praxistest verwendete Scalpel 1.9.0 in einer neuen Laravel-13.31-Anwendung. Mit .env-Rechten auf 0600 und vorhandener Baseline blieb der Standardscan ohne Befund. Danach kamen vier harmlose Testdateien hinzu: eval(base64_decode(...)) in einem if (false)-Block, avatar.php.jpg, eine .htaccess-Handler-Zuordnung und eine .user.ini-Datei mit auto_prepend_file. Die vier Inhaltsprüfungen liefen mit php artisan scalpel:scan --only=structural,obfuscated,htaccess,userini --no-banner. Ein vollständiger Scan meldete neun Treffer, weil Baseline Diff zusätzlich die vier Dateien und eine geänderte routes/web.php erfasste.

Der Test zeigte außerdem ein CI-Problem mit generierten Views. php artisan optimize erzeugte kompilierte Framework-Views unter storage/framework/views. Der nächste Scan meldete dort 100 MEDIUM-Treffer zu variable-variable und zwei HIGH-Treffer zu Backticks. Nach php artisan optimize:clear und einer neuen Baseline war der Scan wieder sauber. Der Structural Scanner erlaubt das Verzeichnis, der Obfuscated-Code-Scanner liest seinen Inhalt jedoch weiterhin. Anwendungen mit gecachten Views in Produktion sollten diesen Pfad vor einem Einsatz als Deployment-Gate prüfen. storage/framework/views in content_scan_excluded_paths entfernt die Treffer, überspringt damit aber Inhaltsprüfungen für alle kompilierten Views.

scan und diff unterstützen Tabellen-, JSON-, GitHub-Actions-Annotation- und SARIF-Ausgaben. --fail-on legt die niedrigste Schwere fest, die einen CI-Job fehlschlagen lässt. Standardmäßig gilt HIGH. Das dokumentierte SARIF-Beispiel lautet php artisan scalpel:scan --format=sarif --fail-on=MEDIUM. Exit-Code 0 bedeutet einen erfolgreichen Scan ohne entsprechenden Befund. Code 1 steht für mindestens einen Treffer ab dem Schwellenwert. Code 2 kennzeichnet niedrigere Treffer oder einen unvollständigen Lauf, etwa wegen eines nicht lesbaren Verzeichnisses.

Nach scalpel:scan oder scalpel:diff löst das Paket ScanFinished aus. Das Event enthält die Befunde, den ausgeführten Befehl, scan oder diff, und die Dauer in Millisekunden. Anwendungen können damit eigene Benachrichtigungen per E-Mail, Slack oder Webhook versenden, ohne die Befehlsausgabe zu parsen.

Laravel Scalpel benötigt PHP 8.2 oder neuer und unterstützt Laravel 10 bis 13. Die Installation erfolgt mit composer require hryagstn/laravel-scalpel. Danach wird die Konfiguration mit php artisan vendor:publish --tag=scalpel-config veröffentlicht. Der Scanner läuft mit demselben Prozess und denselben Dateirechten wie die Anwendung. Wer Anwendungscode verändern kann, kann auch Scanner oder Konfiguration verändern. Das Projekt empfiehlt externe Scan-Auslöser, schreibgeschützte Code-Verzeichnisse und eine Ablage der Ergebnisse außerhalb des möglicherweise kompromittierten Servers. Scalpel liefert Einbruchshinweise, aber keine Firewall- oder Eindämmungsfunktion. Quellcode und Befehlsreferenz stehen auf GitHub bereit, zusätzlich gibt es einen Simulator auf der Laravel-Scalpel-Website.