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 $_POST echoed 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.php and the sink is in helpers.php). It's a pattern matcher, not a flow analyzer.
  • Install: pip install semgrep or 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, then vendor/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->isAdmin but the method is isAdmin()" — 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 a phpstan.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 gitleaks or 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 auth with 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.

Want help picking and wiring up a stack — or just want us to run a scan against a copy of your site and send you the findings? Send the repo or URL below.

We reply within 1–2 business days.