Static analysis is one of the few security controls that runs on every change. It’s also one of the most ignored. When Ghost Security scanned public Go, Python and PHP repositories with traditional SAST tools, 180 of 2,116 flagged vulnerabilities turned out to be real: under 9%. Once developers learn that most alerts are wrong, they stop reading all of them.
The volume is growing. More code is written with AI assistants, and research has shown developers using them can write less secure code while believing it’s more secure. More code means more findings, so the cost of noise rises. The answer isn’t to switch the scanner off. It’s to tune it until developers trust it.
Start by measuring precision
You can’t tune what you haven’t measured. Take the last 100 findings, or all of them if there are fewer, and have someone who knows the code mark each one as real, false positive or not worth fixing. Then group the results by rule.
You’ll usually find that a few rules produce most of the noise. Those are your first targets.
Five ways to cut the noise
1. Turn off rules that don’t apply
Rules for frameworks you don’t use, languages that only appear in test fixtures or classes of bug your platform prevents should go. Exclude generated code, vendored dependencies and test directories from scanning.
2. Teach the tool your sanitisers
Most taint-tracking false positives happen because the tool doesn’t know that your escapeHtml() helper or your ORM’s parameterised query is safe. Register them as sanitisers or safe sinks once, and a whole category of findings disappears.
3. Scan the diff, not the repository
On pull requests, report only findings introduced by the change. The existing backlog is a separate project with its own triage. Developers will act on three findings in their own code. They won’t act on three hundred in someone else’s.
4. Block on a short list
Pick the handful of high-precision rules where a finding should stop a merge, such as hard-coded secrets or SQL built from request input. Everything else is a comment or a ticket. A build that fails on noise teaches people to bypass the build.
5. Write rules for your own bugs
The most valuable rules come from your own history. If a penetration test found a missing ownership check, write a rule for the pattern, so it can’t come back quietly.
rules:
- id: order-lookup-without-owner
message: Order fetched by ID without scoping to the current account
severity: ERROR
languages: [javascript]
pattern: Order.findById($ID)
Know what SAST won’t find
Pattern-matching tools are good at injection, unsafe functions and secrets. They are poor at authorization and business logic, because the bug is something that isn’t there, such as a check nobody wrote. Those need code review and testing. A tuned scanner frees reviewer time for exactly that work.
Keeping it tuned
- Track the false-positive rate per rule every month.
- Make it easy for developers to mark a finding as a false positive, and review those markings.
- Re-check precision after major framework or tool upgrades.
- Add a custom rule after every serious finding from review or testing.
