Taint Analysis False Negative in a Framework
A SAST tool reports zero SQL injection findings across a Java Spring codebase. Manual review finds a repository method that concatenates a sort query parameter into an ORDER BY clause. The tool's taint sources include @RequestParam and @PathVariable, and its sinks include Statement.execute*. The vulnerable code builds the query string and passes it to a JPA EntityManager.createNativeQuery(...).getResultList(), which the tool does not model as a sink. The team's policy is 'no criticals from SAST = ship.' A separate finding shows the same parameter is allow-listed against three column names in one controller but not in a second controller that reuses the service.
1. Explain why the SAST result is a false negative and what this implies about the 'no criticals = ship' policy.
Read the worked answer
The taint engine tracks source→sink flows it models. Here the source (@RequestParam sort) is recognized, but the sink is createNativeQuery(...).getResultList(), which the tool does not treat as an execution sink - so the flow is dropped and no finding is emitted. That is a coverage gap in the tool's sink model, not evidence of safety. The policy 'no criticals = ship' is therefore unsound: absence of findings is bounded by the tool's modeling, and a clean report means 'nothing the tool knows how to find,' not 'nothing exploitable.' The ORDER BY injection is real - column-name injection enables error-based and blind extraction even without a WHERE clause.
2. The allow-list exists in one controller but not the other. What class of bug is this and how do you fix it durably?
Read the worked answer
This is an inconsistent-control / missing-enforcement bug: a security decision is implemented at the controller layer, so any caller that bypasses that controller (the second one, or future ones) skips it. Fix at the layer that owns the data access, not the caller: enforce the allow-list inside the service/repository method so every path is covered, or better, avoid string concatenation - map the sort parameter to a fixed enum of permitted columns and build the ORDER BY from that enum, rejecting anything else. Add a unit test that calls the service directly with a malicious sort value and asserts rejection, so the control is tested where it lives. Then feed the missed sink back to the SAST vendor and add a custom rule so the gap closes for the next scan.