pheromone/phpcs-security-audit
Installation
Add the package via Composer (note: as of writing, the composer require command in the README is outdated; use GitHub URL or wait for v3 release):
composer require --dev pheromone/phpcs-security-audit
This installs the package and registers the Security standard with PHP_CodeSniffer via the DealerDirect/phpcodesniffer-composer-installer plugin.
Verify Installation Check if the standard is registered:
./vendor/bin/phpcs -i
Look for Security in the output.
First Scan Run a basic scan on your Laravel project (adjust extensions as needed):
./vendor/bin/phpcs --standard=Security --extensions=php app/
Scan critical Laravel files (routes, controllers, middleware, and config) for common security issues:
./vendor/bin/phpcs --standard=Security --extensions=php \
--runtime-set=ParanoiaMode,0 \ # Reduce false positives
app/Http/Controllers/ app/Http/Middleware/ routes/ config/
CI/CD Integration Add a PHP_CodeSniffer step to your Laravel CI pipeline (e.g., GitHub Actions):
- name: Run Security Audit
run: ./vendor/bin/phpcs --standard=Security --extensions=php --runtime-set=ParanoiaMode,0 app/
Fail the build on errors (adjust severity as needed):
./vendor/bin/phpcs --standard=Security --extensions=php --warning-severity=3 app/
Pre-Commit Hooks
Use phpcs in a pre-commit hook (e.g., with Laravel Pint or custom scripts) to catch issues early:
# .git/hooks/pre-commit
#!/bin/sh
./vendor/bin/phpcs --standard=Security --extensions=php --runtime-set=ParanoiaMode,0 --report=json app/ > phpcs-results.json
if [ $(jq '.errors | length' phpcs-results.json) -gt 0 ]; then
echo "Security issues found. See phpcs-results.json."
exit 1
fi
Custom Rulesets Extend the default ruleset for Laravel-specific needs:
<!-- phpcs-security-audit.xml -->
<rule ref="Security">
<arg name="ParanoiaMode" value="0"/>
<arg name="CmsFramework" value="Laravel"/>
</rule>
Run with:
./vendor/bin/phpcs --standard=./phpcs-security-audit.xml app/
Middleware and Route Security Focus scans on middleware and route files where user input is commonly handled:
./vendor/bin/phpcs --standard=Security --extensions=php \
--files=app/Http/Middleware/*,routes/*.php
Blade Template Checks
While Blade templates aren’t PHP, scan .php files in resources/views for unsafe echo statements:
./vendor/bin/phpcs --standard=Security --extensions=php resources/views/
Dependency Scanning
Use the package’s CVE checks to audit Laravel dependencies (though this is limited to Drupal by default; extend Utils.php for Laravel):
./vendor/bin/phpcs --standard=Security --extensions=php vendor/
False Positives
htmlspecialchars as unsafe if not used correctly).ParanoiaMode to 0 or customize rules in your XML config:
<rule ref="Security.Sniffs.XSS.DirectEcho">
<properties>
<property name="forceParanoia" value="false"/>
</properties>
</rule>
Performance
./vendor/bin/phpcs --standard=Security --extensions=php --ignore=app/Http/Tests app/ --parallel=4
Drupal-Specific Rules
<rule ref="Security.Sniffs.Drupal7"/>
Short Open Tags
<?= or <?php, but the tool may misinterpret them.short_open_tag is enabled in your php.ini for Blade files (though this is Laravel-specific).Outdated Rules
Utils.php to add Laravel-specific user input detection (e.g., request()->input()).Inspect Warnings
Use --report=json to analyze false positives programmatically:
./vendor/bin/phpcs --standard=Security --extensions=php --report=json app/ > audit.json
jq '.files[] | select(.errors | length > 0)' audit.json
Test Individual Rules Test a specific rule (e.g., XSS checks) in isolation:
./vendor/bin/phpcs --standard=Security --extensions=php --test=Security.Sniffs.XSS.DirectEcho app/
Custom Mitigation Functions
Add Laravel-specific mitigations (e.g., e() helper or Illuminate\Support\Str::of()) to Utils.php:
public static function is_XSS_mitigation($function) {
return parent::is_XSS_mitigation($function) ||
in_array($function, ['e', 'Str::of']);
}
Add Laravel Framework Support
Create a Laravel/ folder in Sniffs/ with a Utils.php to override user input detection:
namespace Pheromone\PHP_CodeSniffer\Standards\Security\Sniffs\Laravel;
class Utils extends \Pheromone\PHP_CodeSniffer\Standards\Security\Sniffs\Utils {
public static function is_direct_user_input($var) {
if (parent::is_direct_user_input($var)) {
return true;
}
return in_array($var, ['request', 'input', 'get', 'post']);
}
}
Update your ruleset:
<arg name="CmsFramework" value="Laravel"/>
Custom Severity Rules
Override severity for specific rules (e.g., treat preg_replace with /e as a warning):
<rule ref="Security.Sniffs.BadFunctions.PregReplaceEModifier">
<severity>2</severity>
</rule>
Integrate with Laravel Testing Run security audits in PHPUnit tests:
// tests/Feature/SecurityAuditTest.php
public function test_security_audit() {
$exitCode = Artisan::call('phpcs', [
'--standard=Security',
'--extensions=php',
'--runtime-set=ParanoiaMode,0',
'app/Http/Controllers',
]);
$this->assertEquals(0, $exitCode, 'Security audit failed');
}
How can I help you explore Laravel packages today?