I’ve scanned codebases that passed every SAST tool — SonarQube, Semgrep, CodeQL, Coverity — and found critical vulnerabilities within the first hour of manual review. Not because the tools are bad, but because they operate in a category that misses the most dangerous class of bugs.
Here’s what they miss and why.
1. Exploit Chains (CWE-1104)
What it is: Two or more individually benign bugs that become critical when combined.
Why scanners miss it: Tools evaluate each finding independently. A null pointer dereference in function A and a race condition in function B are both filed as separate Medium-severity issues. No tool asks “what happens if an attacker triggers both at the same time?”
Real example: Chrome CVE-2022-3075. A nullptr validator (flagged as Low by most scanners) combined with a follow-on accessor that trusted the now-null pointer. The chain produced a 9.6 CVSS sandbox escape. Both individual bugs were known. The chain was found by a human.
2. Two-Phase API TOCTOU (CWE-367)
What it is: An API with separate validate and execute steps — an attacker changes state between them.
Why scanners miss it: The validate function and the execute function are often in different files, different classes, or different compilation units. A scanner sees two independent functions. A human sees a time-of-check / time-of-use window.
// File A: validate_user_request(req)
// Checks permissions, returns true/false
// File B: process_user_request(req)
// Trusts the earlier validation without rechecking
The gap between A and B is invisible to static analysis but trivially exploitable.
3. Context-Dependent Hardcoded Credentials
What it is: A credential that’s harmless in isolation but catastrophic in context.
Why scanners miss it: Tools flag AIzaSy* patterns and call it done. They don’t ask “what API does this key unlock?” and “what can an attacker do with it?”
During an Instagram APK audit, I found 241 HTTP-only URL references. A scanner flagged “Cleartext HTTP.” What it missed: those URLs included {claimSecret} tokens in path parameters for financial payout endpoints. Not just cleartext — cleartext money.
4. Information Debt
What it is: Code that reveals sensitive behavior through its error messages, timing, or side channels.
Why scanners miss it: Information leaks don’t follow a pattern. A 500 response that says “SQL error at line 47: invalid column name” vs. “Internal Server Error” — both are error responses, but one reveals your database schema. The difference is semantic, not syntactic.
5. Cross-Boundary State Confusion
What it is: A pattern that’s safe within one trust boundary but exploitable across boundaries.
Why scanners miss it: Most tools analyze a single codebase at a single privilege level. They don’t understand that a DCHECK in a browser process is a security boundary guard that compiles out in release.
This is the bug class I documented in Chrome’s DCHECK-as-security-boundary report: 15+ locations where DCHECK(offset < num_elements) is the only guard between attacker-controlled input and raw memory access. Every SAST tool sees a bounds check. No tool asks “is this check compiled out in production?”
The Human Difference
I don’t find these bugs because I’m smarter than the tools. I find them because I ask different questions:
- “If this check fails, what happens next?”
- “What can an attacker do BETWEEN these two operations?”
- “If I chain Finding A with Finding B, what does the attack look like?”
- “What does this error message tell someone who wants to exploit this system?”
- “Is this guard present in the release binary?”
SAST tools check syntax. I check for adversarial possibilities. If your codebase has been “scanned clean” by automated tools, that doesn’t mean it’s clean — it means no one has asked the right questions yet.
Want a second opinion? Send me your repo for a free sample audit. I’ll find what the scanners missed and send you a report in 48 hours.
Part of the Geometric Vulnerability Analysis series