nth-root / phpstan-security
A PHPStan extension that checks your code for security vulnerabilities
Package info
github.com/nth-root/phpstan-security
Type:phpstan-extension
pkg:composer/nth-root/phpstan-security
Requires
- php: ^8.2
- phpstan/phpstan: ^2.1.3
Requires (Dev)
- doctrine/dbal: ^4.0
- friendsofphp/php-cs-fixer: ^3.95
- phpunit/phpunit: ^11.5 || ^12.0 || ^13.4
- symfony/framework-bundle: ^7.4
- symfony/http-foundation: ^7.4
- symfony/http-kernel: ^7.4
- symfony/process: ^7.4
- symfony/routing: ^7.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
An extension for PHPStan that detects common security vulnerabilities in PHP code.
Its main feature is taint analysis: following user input ($_GET,
Symfony's and Laravel's Request objects and route parameters) through variables and function calls, and reporting when it reaches a
dangerous location such as a SQL query, a shell command, or echo.
Because it analyzes the whole project at once, it also catches input that a controller passes to a service or repository
in another file.
Warning
This extension is experimental and under active development. Error identifiers, configuration and behavior may change between releases. A clean run does not mean your code is free of vulnerabilities.
Detected vulnerabilities
| Vulnerability | Identifier | Supported sinks |
|---|---|---|
| SQL injection | tainted.sql |
PDO, mysqli, SQLite3, Doctrine DBAL Connection, Laravel connections and query builders |
| Cross-site scripting (XSS) | tainted.html |
echo, print, printf(), vprintf() |
| Command injection | tainted.shell |
exec(), system(), shell_exec(), backticks, ... |
| Path traversal, SSRF | tainted.path |
file_get_contents(), fopen(), unlink(), ... |
| File inclusion | tainted.include |
include, include_once, require, require_once |
| Open redirect | tainted.redirect |
header() with a Location: or Refresh: header |
User input is detected from:
$_GET,$_POST,$_REQUEST,$_COOKIE- Symfony's
Requestand itsquery,request,cookiesandheadersbags - Laravel's
Request(input(),query(),all(),header(), ...) - Controller arguments that match a
{placeholder}in a#[Route]attribute
Installation
composer require --dev nth-root/phpstan-security
If you use phpstan/extension-installer, that's all. Otherwise,
include the extension in your phpstan.neon:
includes: - vendor/nth-root/phpstan-security/extension.neon
Ignoring findings
To ignore a single finding, use a @phpstan-ignore PHPDoc tag with the identifier:
/** @phpstan-ignore tainted.sql */ $connection->executeQuery($sql);
Or ignore a whole category of findings with ignoreErrors in phpstan.neon:
parameters: ignoreErrors: - identifier: tainted.sql
Known limitations
The analysis only follows tainted data through code it understands.
$_SERVERand$request->attributesare not detected as sources yet.- Built-in functions that aren't configured as a flow function stop taint.
That currently includes sanitizers like
htmlspecialchars()andescapeshellarg(). - Return values of user-defined functions and methods aren't followed yet.
- Values assigned to properties (
$this->query = $input) or array elements ($arr['q'] = $input) aren't followed yet. - The analysis is flow-insensitive: once a variable holds user input, it is considered tainted in that function, even if it is overwritten at a later point.
- Symfony route parameters are only treated as user input for routes defined with
#[Route]attributes. Other routing configuration (YAML, XML, PHP) is not read. - Twig templates aren't analyzed, so XSS through
{{ ... |raw }}isn't detected. - Laravel facade calls that are sinks or sources themselves (
DB::select(),Request::input()) aren't detected yet. - Laravel's
$request->name, therequest()helper, and methods called on$request->string()aren't followed yet. - Laravel route parameters from
routes/*.phparen't treated as user input. - Blade templates aren't analyzed, so XSS through
{!! ... !!}isn't detected.