Scan the filesystem for rogue PHP, tampered server rules, and unexpected changes. Get an evidence-first report from a zero-dependency Artisan package.
composer require hryagstn/laravel-scalpel
Application logs tell you what ran. Scalpel checks what is actually present in your project and highlights evidence that needs investigation.
Attackers quietly drop obfuscated PHP webshells inside public assets directories or storage
zones (e.g. public/icons/avatar.php) disguised as generic assets. Traditional WAFs
and error trackers miss them because they don't throw application exceptions.
By altering root or directory .htaccess rules, intruders can force servers to map
Python or Perl interpreters to custom MIME types, enabling them to execute raw terminal scripts
via normal HTTP requests.
Malicious actors routinely delete or truncate your application's .env
configurations. This silences monitoring endpoints, disables error-log tracking libraries, and
resets security keys, blinding your incident response.
.env disappearing..htaccess..env structural state and readability.Laravel Scalpel divides its work into individual checkers, each focusing on a distinct indicator of system compromise.
Flags PHP script extensions hidden inside static zones like public/,
storage/, and bootstrap/cache/.
non_php_zones.phtml, .pht, .phar, .php5shell.php.jpgindex.php)Deconstructs all project PHP sources to identify obfuscated payloads, webshell triggers, and base64 payloads.
eval(base64_decode), superglobal_eval, dynamic_includecreate_function & encoded file_put_contents droppers$$var indirection & extract($_REQUEST)chr() chaining, hex sequences, long strings (>=500 chars)
Audits Apache configurations for injected rules changing handler maps to trigger external
scripts (Python, Perl) — plus the PHP-FPM equivalent, .user.ini.
AddHandler triggers.user.ini persistence via auto_prepend_fileallow_url_include, emptied disable_functions)Calculates cryptographic checksum hashes for codebases. Instantly reveals files that were altered, deleted, or injected.
baseline.json snapshots--fast option for deferred hashingValidates the local state of critical variables, guarding configuration blocks against deletion or tampering.
.envAPP_KEY & flags APP_DEBUG=true in production.env.example both waysAn honest overview of process isolation, potential attack surfaces, and production mitigations.
laravel-scalpel operates as a detection layer rather than a containment or sandbox layer. Because it is executed as a PHP Artisan command within your web-application workspace, it:
www-data).⚠️ Attacker Tampering Risk: A sufficiently skilled intruder who obtains raw PHP file execution could alter the scanner code, override configuration keys, or intercept report generation before results are dispatched.
Sign JSON scan outputs via HMAC-SHA256 to guarantee integrity. Any post-scan report modifications during transport are caught instantly by scalpel:verify.
Trigger scans externally via secure cron contexts running as distinct user profiles. Pair with read-only containers (Docker) to keep code zones immune to write modifications.
Manage rules, adjust obfuscation filters, declare safe directories, and trigger alerts through modern integrations.
<?php
return [
// Directories where PHP files should NOT exist
'non_php_zones' => [
'public',
'storage',
],
// Whitelisted PHP files within static directories
'structural_allowed_files' => [
'public/index.php',
],
// Subdirectories within static zones where PHP files are expected
'structural_allowed_directories' => [
'public/vendor',
'storage/framework/views',
'storage/framework/cache',
],
// Excluded from ALL scans
'excluded_paths' => [
'node_modules',
'.git',
],
// Excluded from content scanners only (still checked by baseline)
'content_scan_excluded_paths' => [
'vendor',
'bootstrap/cache',
],
// Extensions treated as executable PHP (incl. disguised webshells)
'suspicious_php_extensions' => [
'php', 'pht', 'phtm', 'phtml', 'phar', 'php5',
],
// Target obfuscation regex checks
'obfuscation_patterns' => [
'eval_base64_decode' => true,
'eval_gzinflate' => true,
'eval_str_rot13' => true,
'eval_gzuncompress' => true,
'eval_gzdecode' => true,
'assert_dynamic' => true,
'backtick_operator' => true,
'variable_variables' => true,
'extract_input' => true,
'variable_functions' => true,
'preg_replace_e' => true,
'long_encoded_string' => true,
'create_function' => true,
'file_put_contents_encoded' => true,
'superglobal_eval' => true,
'chr_chaining' => true,
'hex_escape_sequence' => true,
'dynamic_include' => true,
],
'long_string_threshold' => 500,
'severity_threshold' => 'LOW',
// Hide the banner in cron jobs and CI logs
'suppress_banner' => env('SCALPEL_SUPPRESS_BANNER', false),
// Use metadata-based fast scans; set true via --fast parameter or env override
'baseline_fast_scan' => env('SCALPEL_BASELINE_FAST_SCAN', false),
'baseline_disk' => env('SCALPEL_BASELINE_DISK', 'local'),
// Force strict production environment checks
'assume_production' => env('SCALPEL_ASSUME_PRODUCTION', false),
// Output HMAC signature signing settings
'signing' => [
'enabled' => env('SCALPEL_SIGNING_ENABLED', false),
'key' => env('SCALPEL_SIGNING_KEY'),
],
];
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * *' # Daily at 6 AM UTC
jobs:
scalpel-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install Dependencies
run: composer install --no-interaction --prefer-dist
# Annotations render inline on pull requests (::error / ::warning)
- name: Run Scalpel Scan
continue-on-error: true
run: php artisan scalpel:scan --format=sarif > scalpel.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: scalpel.sarif
- name: Run Baseline Diff
run: php artisan scalpel:diff --format=json
# Pair laravel-scalpel with n8n-bastion to receive instant Telegram notifications
# when a CRITICAL vulnerability or filesystem alteration occurs on your production VPS.
# Example bash hook triggered by cron on your VPS server:
RESULT=$(php artisan scalpel:scan --format=json)
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
# Verify the report was not tampered with before dispatching
if php artisan scalpel:verify /tmp/scalpel-output.json; then
curl -X POST https://your-n8n-bastion-domain.com/webhook/scalpel-alert \
-H "Content-Type: application/json" \
-d "{\"status\": \"compromised\", \"findings\": $RESULT}"
fi
fi
use Hryagstn\Scalpel\Events\ScanFinished;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
public function boot(): void
{
Event::listen(ScanFinished::class, function (ScanFinished $event) {
// $event->findings, $event->context ('scan'|'diff'), $event->durationMs
if ($event->findings->hasCriticalOrHigh()) {
Mail::to('security@example.com')
->send(new \App\Mail\ScalpelAlert($event->findings));
}
});
}
Integrate Laravel Scalpel into your codebase in less than a minute.
Pull the scanner package into your project vendor using Composer.
composer require hryagstn/laravel-scalpel
Generate your config asset template file config/scalpel.php.
php artisan vendor:publish --tag=scalpel-config
Audit your directories or create baseline snapshots of your codebase.
php artisan scalpel:scan
Combine filesystem scans with other open-source tooling from the same developer for maximum visibility.
A self-hosted open-source server security monitor template designed for VPS administrators. Combined with Laravel Scalpel, it watches server performance metrics, process counts, and forwards urgent security threat updates directly to your Telegram chat.