Articles / What SAST Actually Catches — and What It Misses
AppSec · SAST Fundamentals

What SAST Actually Catches — and What It Misses

Static Application Security Testing reads your source code without running it, models how data moves through the program, and flags patterns that look dangerous. That model is powerful and it is also incomplete. The single most common cause of a failed SAST rollout is not a bad tool — it is a team that expected the tool to find things it structurally cannot, and stopped trusting it when it didn't.

SAST works by parsing code into an abstract syntax tree, building a control-flow and data-flow model, and matching that model against rules. Because it never executes the program, it can reason about every branch at once — including error paths a test suite never triggers — and it can point at the exact file and line. That is its great strength: coverage and precision of location, available the moment code is written, long before anything is deployed.

What it catches well

Source codeParse to AST+ control/data flowFlow modelMatch rulestaint patternsFindingfile + lineIDOR, businesslogic, config liveoutside the code →structurallyinvisible
How SAST sees code — and the bug classes that never appear in its model.

The sweet spot for SAST is any vulnerability where an untrusted value flows through the code into a dangerous operation, and both ends are visible in the source. That covers a large slice of the classic bug catalogue.

  • Injection with traceable data flow. SQL injection, OS command injection, path traversal, and LDAP injection — wherever a request parameter reaches a query or a shell without sanitisation, taint tracking can follow it.
  • Cross-site scripting in server-rendered output. Untrusted input written into an HTML response without encoding is a textbook source-to-sink pattern.
  • Hardcoded secrets and weak cryptography. API keys in source, use of MD5 for passwords, ECB mode, disabled certificate validation — these are syntactic tells a rule can match reliably.
  • Dangerous API usage. Insecure deserialisation entry points, unsafe reflection, XXE-prone parser configuration, and known-bad function calls are pattern matches SAST excels at.
Why it matters: SAST is a code-shaped lens. It sees flaws that live in the code and are visible from the code. The further a bug's cause sits from the source text, the blinder the tool becomes.

What it misses

The blind spots are not tuning problems; they are consequences of never running the program and never knowing your intent. A scanner cannot tell that invoice_id belongs to a different tenant, because nothing in the syntax says so.

  • Broken access control and authorization. IDOR and BOLA depend on business rules about who owns what. The code that fetches the wrong record looks identical to the code that fetches the right one.
  • Business-logic flaws. A negative-quantity checkout, a coupon applied twice, a workflow step skipped — these are correct code doing the wrong thing.
  • Runtime and environment issues. A permissive CORS policy set by a load balancer, a secret injected at deploy time, a misconfigured bucket — none of it is in the application source.
  • Flow the analyser can't follow. Heavy reflection, dynamic dispatch, ORM magic, or data that leaves the process and returns can break taint tracking and produce false negatives that look like a clean bill of health.
Two lines a scanner cannot tell apartreturn db.query("SELECT * FROM invoices WHERE id = ?", id); // safe if id is yours
return db.query("SELECT * FROM invoices WHERE id = ?", id); // IDOR if id is someone else's

Using the line, not fighting it

The mature posture is to treat SAST as one instrument in a set. Pair it with dynamic testing for runtime and configuration issues, with access-control test cases for authorization, and with dependency scanning for the code you didn't write. Feed its false negatives back into custom rules, and never read a clean SAST run as “no vulnerabilities” — read it as “none of the patterns we taught it to find.”

Knowing the boundary is itself a security control. A team that can name what its scanner cannot see knows where to point its other tools — and you cannot cover a gap you have not discovered.

Test for it — in practice
  • Take a known access-control or IDOR-class issue in your app and check whether a SAST run flagged it — if the code that fetches the wrong record looks identical to the right one, the tool structurally cannot.
  • Read a recent clean SAST report as "none of the patterns we taught it to find", and ask which bug classes you are covering with other tools.

Knowing the boundary is step one; mapping exactly which classes your tooling misses and covering each is what our assessment runs for you.

Keep reading
SAST vs DAST vs IAST: Choosing the Right Lens