Free PHP security scanners (and what each one misses)
A practical comparison of the free, open-source tools that scan PHP code for security issues — what each one catches, what it doesn't, and which combinations actually cover the OWASP Top 10.
There is no single tool that catches every PHP security issue. There are about eight free ones that each catch a different slice. The right strategy is to layer two or three of them so the slices overlap on the things that matter most. This page is the honest comparison — what each tool actually does, what it doesn't, and which stack to assemble for which goal.
The tools, one by one
Semgrep
Pattern-matching static analyzer. You write rules in YAML; it walks the AST of your code and flags matches. The community registry has a few hundred PHP rules covering SQL injection, XSS, command injection, weak crypto, framework-bypass patterns.
- Catches: string concatenation in SQL queries, raw
$_POSTechoed to the page,md5(uniqid())for tokens,header('Location: ' . $...)from user input,eval()on tainted data, dozens more. - Misses: anything that requires cross-function reasoning (where the source is in
controller.phpand the sink is inhelpers.php). It's a pattern matcher, not a flow analyzer. - Install:
pip install semgrepor run the Docker image. ~30 seconds for a small project. - Best for: the first scan you run. Fastest signal, lowest install cost, framework-aware rule packs exist for common stacks.
Psalm
Type analyzer with serious taint-tracking support. Marks $_GET, $_POST,
and friends as tainted sources, follows them through every assignment, function call, and
return statement, flags every dangerous sink they reach. Catches the cross-function cases
Semgrep misses.
- Catches: user input flowing into SQL queries, HTML output, shell commands, file paths, SSRF sinks — even when it goes through three function calls in between.
- Misses: patterns it doesn't have stubs for. If your framework wraps user input in a custom class, Psalm needs an annotation to know whether the unwrap is sanitizing or just passing through. UserSpice has stubs shipped with the Security Scanner; other frameworks may need you to write them.
- Install:
composer require --dev vimeo/psalm, thenvendor/bin/psalm --init. Slower than Semgrep on first run — has to do full type inference. - Best for: finding real cross-file vulnerabilities. Worth the setup cost on any non-trivial codebase.
PHPStan
Type / quality analyzer. Sibling of Psalm in spirit, with a different feature emphasis — stronger on correctness ("this method returns void but you assigned the result"), weaker on security taint analysis. Useful as a complement, not a replacement.
- Catches: type errors, dead code, undefined methods/variables, logic bugs that lead to security issues indirectly (e.g. "you checked
$user->isAdminbut the method isisAdmin()" — the property is always falsy, so the check always passes). - Misses: the security stuff Psalm catches. Different tool, different focus.
- Install:
composer require --dev phpstan/phpstan. Configure aphpstan.neon. - Best for: running alongside Psalm. The two tools' findings overlap less than you'd expect.
Trivy
Dependency scanner. Reads your composer.lock (and package-lock.json,
Dockerfile, IaC configs) and looks up every pinned version against CVE databases.
- Catches: known CVEs in your transitive dependencies. The "your dependency has a known RCE that you don't know about because it's three levels deep" case.
- Misses: bugs in your code. CVEs that haven't been published yet. CVEs in software outside your
composer.lock(like the PHP binary itself, or the web server). - Install:
brew install trivy/apt install trivy/ Docker image. Lookups are fast; runs against the lock file, not the source. - Best for: CI gate. Run it on every build; fail on critical CVEs.
Gitleaks
Secrets scanner. Looks for things shaped like API keys (AWS, Stripe, GitHub, OpenAI…) in your working tree and your git history.
- Catches: hardcoded API keys, tokens, passwords, private keys, even in commits you reverted. The thing that finds the embarrassing key you committed in 2022 and forgot about.
- Misses: secrets that don't match a known pattern (custom token formats, internal credentials with no fingerprint). False positives on placeholder values are common — tune the allowlist.
- Install:
brew install gitleaksor Docker. Scans the whole git history fast (a small repo in seconds). - Best for: one-time history audit + pre-commit hook. Set it up once, forget about it until someone tries to commit a key.
OWASP ZAP
Dynamic application scanner. Crawls your running site, sends test payloads, watches the responses. The only tool in this list that finds runtime issues (missing headers, cookies without flags, server-version leaks, runtime XSS in rendered pages).
- Catches: missing security headers, insecure cookie flags, runtime XSS, info leaks in error pages, SQL injection that manifests as visible behaviour difference.
- Misses: bugs that don't trigger on its crawler payloads. Anything behind auth requires configured login (and that configuration is finicky).
- Install: Docker image. Runs against a deployed URL — needs a running site, can't scan source.
- Best for: staging-environment pre-launch scan. Do not run the full active scan against production — it sends tens of thousands of attack payloads and will trip WAFs, fill your forms with garbage, and possibly break things.
Snyk (free tier)
Commercial product with a generous free tier for open-source / individual use. Dependency scanning, license compliance, some SAST.
- Catches: CVEs in dependencies (like Trivy), some PHP security patterns via SAST.
- Misses: what the paid tier catches but the free tier doesn't (rate-limited scan counts, no on-premises option, narrower rule set).
- Install:
npm install -g snyk+snyk authwith a free account. - Best for: teams that want a hosted dashboard with no infrastructure to maintain. Less ideal if you don't want a third party seeing your code or if you might outgrow the free tier mid-project.
composer audit (built-in)
Composer's own dependency vulnerability checker, added in 2.4. Free with your existing Composer install.
- Catches: CVEs in your direct and transitive Composer dependencies, using the FriendsOfPHP Security Advisories database.
- Misses: bugs in your code; non-Composer dependencies. The advisory database is curated but smaller than Trivy's.
- Install: nothing — you already have it if you have PHP 8.1+ and Composer 2.4+.
composer audit. - Best for: CI gates where you want zero setup overhead. Pair with Trivy if you want broader coverage.
Coverage matrix
Which tool catches which class of bug. ● = primary detection, ◐ = partial / contextual, ○ = not really its job.
| Issue class | Semgrep | Psalm | PHPStan | Trivy | Gitleaks | ZAP | composer audit |
|---|---|---|---|---|---|---|---|
| SQL injection | ● | ● | ○ | ○ | ○ | ◐ | ○ |
| XSS (stored / reflected) | ● | ● | ○ | ○ | ○ | ● | ○ |
| Missing CSRF | ◐ | ○ | ○ | ○ | ○ | ● | ○ |
| Open redirect | ● | ● | ○ | ○ | ○ | ◐ | ○ |
| Weak crypto / random | ● | ◐ | ○ | ○ | ○ | ○ | ○ |
| Hardcoded secrets | ◐ | ○ | ○ | ◐ | ● | ○ | ○ |
| Dependency CVEs | ○ | ○ | ○ | ● | ○ | ○ | ● |
| Missing security headers | ○ | ○ | ○ | ○ | ○ | ● | ○ |
| Unsafe deserialization | ● | ● | ○ | ○ | ○ | ○ | ○ |
| Logic bugs / type errors | ○ | ◐ | ● | ○ | ○ | ○ | ○ |
Recommended stacks
Three sensible combinations, depending on what you're optimizing for.
Tier 1 — minimum viable (zero setup cost)
composer audit + Gitleaks + Semgrep.
Zero install pain (composer audit is built-in), three commands total. Catches
dependency CVEs, leaked secrets, and the most common source-code patterns. Will not catch
cross-function vulnerabilities, but catches everything that's an obvious local pattern.
Run it before every deploy.
Tier 2 — real pre-launch coverage
Tier 1 + Psalm + OWASP ZAP (quick profile against staging).
Adds cross-function taint analysis and runtime detection. Now you're catching the bugs that hide behind three function calls and the bugs that only show up at runtime (missing headers, weak cookies). Sufficient for a real product launch with paying users.
Tier 3 — continuous CI gate
Tier 2 + PHPStan + Trivy + thresholded ZAP active scans against a regenerated staging environment.
All seven tools wired into your CI, each with a severity threshold that fails the build.
Trivy alongside composer audit because the two databases overlap but don't
duplicate. Suitable for a real engineering team running CI/CD with production users.
Or skip the assembly
Tier 3 is six tools to install, configure, and keep updated. Doable, but it's a real chunk of work — especially the Psalm stubs for your framework and the ZAP profile tuning. The Security Scanner bundles all of them into one bash entry point with UserSpice-aware rule packs out of the box. Same tools, same output formats, one install command.
If you're not on UserSpice, the individual tools above are the right starting point — read the comparison, pick your tier, install. If you are on UserSpice and you'd rather not assemble the stack yourself, the bundled scanner is the shortcut.
Want a hosted scan, or help wiring this up?
If you want a one-time scan run against a copy of your site without setting any of this up yourself, or you want help wiring a Tier 2/3 stack into your CI, the form below is the fastest way to reach us.