What Is Laravel Scalpel?
Laravel Scalpel is an intrusion evidence scanner built by Harry Agustiana. Unlike tools such as Ward or Checkpoint—which audit source code and dependencies for known vulnerabilities—Scalpel focuses on a different question: have files in your deployed application already been added, changed, or removed?
It runs as a set of Artisan commands inside a Laravel application and requires PHP 8.2+ with Laravel 10 through 13.
The Six Built-in Scanners
Running php artisan scalpel:scan executes six scanners by default.
Structural Scanner
Looks for executable PHP files in directories where PHP should not appear—public/ and storage/ by default. It catches .php, .phtml, .pht, .phar, and double-extension files such as shell.php.jpg. Known-good paths like public/index.php and compiled views are allow-listed by default.
Obfuscated-Code Scanner
Checks PHP files for common backdoor patterns: eval(base64_decode(...)), compressed payload execution, dynamic function calls, direct evaluation of request input, and long encoded strings. Individual patterns can be disabled in config/scalpel.php if legitimate code triggers a false positive.
.htaccess Scanner
Flags handler and MIME-type mappings that allow the web server to execute Python, Perl, or CGI scripts, as well as Options +ExecCGI, external-URL rewrite rules, and directives like auto_prepend_file.
.user.ini Scanner
Reports per-directory PHP directives including auto_prepend_file, auto_append_file, include_path, and disable_functions—all of which an attacker can exploit to run hidden code on every request.
Environment Scanner
Checks for a missing, empty, or world-readable .env file, a .env placed under public/, an empty APP_KEY, key mismatches against .env.example, and APP_DEBUG=true in production.
Baseline Diff Scanner
Compares current files against a saved SHA-256 snapshot and reports added, modified, and deleted files.
Creating and Using a Baseline
# Record a trusted snapshot
php artisan scalpel:baseline
# Compare current files against it
php artisan scalpel:diff
Create the baseline only when the application is in a state you trust. After each deployment, the recommended workflow is:
php artisan optimize
php artisan scalpel:baseline --force
The vendor/ directory is excluded from content scans but included in baseline comparisons, so a file injected into an installed package still appears in the diff.
Fast Mode vs. Strict Mode
By default, Scalpel hashes every file on each run (strict mode). The --fast flag skips re-hashing when file size and modification time are unchanged—useful for large codebases, but it can miss a tampered file if an attacker preserves both attributes.
Signed Baselines
Set SCALPEL_SIGNING_ENABLED=true and provide a dedicated SCALPEL_SIGNING_KEY (not your APP_KEY) to HMAC-sign baselines and JSON reports. The diff command verifies the signature before use and raises a CRITICAL finding if it is invalid or missing.
Running Selective Scans and CI Integration
# Run only specific scanners
php artisan scalpel:scan --only=structural,obfuscated
# Output SARIF for CI and fail on MEDIUM or higher
php artisan scalpel:scan --format=sarif --fail-on=MEDIUM
Exit codes: 0 = clean, 1 = finding at or above --fail-on severity, 2 = findings below threshold or incomplete scan.
After each scan or diff, Scalpel dispatches a ScanFinished event containing findings, command name, and duration in milliseconds—making it straightforward to route alerts to Slack, email, or a webhook without parsing CLI output.
Note for CI pipelines: php artisan optimize compiles views under storage/framework/views. The obfuscated-code scanner reads those generated files and can produce many false positives. Add storage/framework/views to content_scan_excluded_paths or run optimize:clear before scanning.
Installation
composer require hryagstn/laravel-scalpel
php artisan vendor:publish --tag=scalpel-config
Key Takeaways
- Scalpel detects post-compromise evidence; it is not a firewall or WAF.
- Six scanners cover structural anomalies, obfuscated code,
.htaccess/.user.initampering, environment issues, and baseline drift. - Signed baselines add tamper detection but cannot protect against an attacker who can read the signing key.
- CI-friendly output formats (JSON, SARIF, GitHub Actions annotations) and configurable
--fail-onseverity make it easy to integrate into deployment pipelines. - The scanner runs with the same permissions as the application—use external scan triggers and read-only code directories for stronger guarantees.
Source: Laravel News — Laravel Scalpel Scans for Filesystem Intrusion Evidence