Frameworks & libraries scanned
We test fixture coverage on these frameworks. New patterns are added with each builtin rule release.
Top CWE classes detected
These CWE classes appear most often in modern codebases of this language. StaticCodeAudit ships dedicated rules for each, mapped to OWASP Top 10 / ISO 27001 / ASVS where relevant.
CWE-89
SQL Injection
mysql_query("... " . $_GET['id']), $pdo->query() with concat, Laravel DB::raw() with user input, WordPress $wpdb->query with unescaped vars.
Detected by SCA rule: sql_injection_concat
CWE-79
Cross-Site Scripting (XSS)
echo $_GET['name'] without htmlspecialchars, Twig {{ var|raw }}, WordPress esc_attr missing on echoed user data.
Detected by SCA rule: xss_raw_html
CWE-78
OS Command Injection
system($cmd), exec(), shell_exec(), passthru() with user input. PHP's shell functions interpret metacharacters by default.
Detected by SCA rule: command_injection_php
CWE-98
File Inclusion (RFI/LFI)
include $_GET['page'] or require with user-controlled paths. Allows arbitrary file read, sometimes remote code execution.
Detected by SCA rule: path_traversal_os_join
CWE-502
Insecure Deserialization
unserialize($_GET['data']) on user input. PHP's native serialization is a known gadget vector (phpggc).
Detected by SCA rule: unsafe_deserialization
CWE-798
Hardcoded Credentials
DB credentials in config.php committed, WordPress wp-config.php in public repo, API keys as constants.
Detected by SCA rule: hardcoded_secret
Vulnerable vs. clean — three quick examples
CWE-89
Detected by SCA rule: sql_injection_concat
// Vulnerable — direct concatenation
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
$result = $mysqli->query($sql);
// Clean — prepared statement
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
CWE-79
Detected by SCA rule: xss_raw_html
// Vulnerable — raw echo
echo "<p>Hello, " . $_GET['name'] . "</p>";
// Clean — htmlspecialchars with ENT_QUOTES + UTF-8
echo "<p>Hello, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8') . "</p>";
CWE-78
Detected by SCA rule: command_injection_php
// Vulnerable — shell metacharacter abuse
system("convert " . $_FILES['img']['tmp_name'] . " /var/thumb.jpg");
// Clean — escapeshellarg + 2-argument form
$src = escapeshellarg($_FILES['img']['tmp_name']);
system("convert {$src} /var/thumb.jpg");
What StaticCodeAudit detects (this language)
- SQL injection in PDO concat, mysqli without prepared statements, Laravel DB::raw, WordPress $wpdb concat
- XSS via raw echo, Twig
|raw, missinghtmlspecialchars/esc_attr - Command injection in
system,exec,shell_exec,passthru,popen - File inclusion (LFI/RFI) via
include,requireon user-controlled paths - Insecure deserialization via
unserializeon user data - Hardcoded credentials in
config.php,wp-config.php,.envcommitted - Insecure session config (
session.cookie_secure,session.cookie_httponlyoff) - Open redirect via
header("Location: " . $_GET['url']) - Path traversal in
file_get_contents,fopenwith user paths - Insecure crypto (MD5/SHA1, mcrypt deprecated, hardcoded keys/IVs)
- CSRF token missing on POST endpoints
- PHP error display enabled in production (
display_errors=On) - Deprecated APIs (mysql_*, ereg, split, php-fpm pm.user=root)
- CI/CD misconfigurations (.gitlab-ci, GitHub Actions, Composer scripts)
CVE Test Suite — Laravel and PHP stdlib
StaticCodeAudit was measured against a real-world CVE Test Suite: 45 cases reconstructed from published, historical CVEs across 8 frameworks and 5 languages. Laravel and the PHP standard library are both in it.
By framework, CVE-reconstructed
Laravel scores 100% precision at 66.7% recall; PHP stdlib scores 80.0% precision at 66.7% recall — solid, not perfect: some real historical CVEs in both still slip through. Full cross-language breakdown (including where ASP.NET and Express score lower) on the <a href="/language-benchmarks.php" class="text-primary font-semibold hover:underline">language benchmarks page</a>.
Real vulnerabilities rarely live in one file
Laravel applications split logic across layers: a controller receives the request, a model or query builder builds the query. A scanner limited to one file at a time never connects the two — it sees user input in OrderController.php and a database call in Order.php, but never the link between them. StaticCodeAudit follows the data across files.
public function show(Request $request)
{
$id = $request->query('id');
return Order::find($id);
}
public static function find($id)
{
return DB::select(
"SELECT * FROM orders WHERE id = $id"
);
}
id comes from the query string in the controller, and reaches the raw SQL query one file later, unmodified — StaticCodeAudit reports it at the exact line where the query runs.
How does this compare to Psalm or Semgrep?
Psalm's taint-analysis mode and Semgrep are the two tools that come up first when a PHP team looks for a free security scanner. Both are legitimate, and many teams already run one of them — here's an honest comparison, not a takedown.
Psalm (taint mode)
Free, open-sourceStatic analyzer built primarily for type-checking, with an opt-in taint-analysis mode that tracks user input to dangerous sinks (SQLi, XSS, command injection). Solid engine, but the security mode needs explicit configuration and type annotations to be effective, and findings aren't mapped to CWE/ISO 27001/ASVS out of the box.
Semgrep (Community)
Free, open-source corePattern-matching engine covering many languages, including PHP, with a large open rule registry. The free tier covers most day-to-day rules; cross-file taint tracking, compliance reporting and some enterprise integrations sit behind Semgrep's paid tiers.
Full StaticCodeAudit vs Semgrep comparison →Neither of these gets replaced by installing StaticCodeAudit — if Psalm already flags what your team needs, keep running it. What StaticCodeAudit adds on top: findings pre-mapped to CWE/OWASP/ISO 27001/ASVS/NIST CSF (a finding that's audit-ready, not just a rule ID), taint tracking that works out of the box without prior type-annotation work, and 7 other languages covered by the same binary — no separate scanner to configure per language. Many teams run both.
Audit your codebase
Audit Laravel, Symfony, WordPress and legacy PHP for SQL injection, XSS, file inclusion, and configuration drift — without uploading code to any third-party cloud.
Download demo binary Book a walkthrough