AppSec · Dec 17, 2025 · 6 min read

Reachable beats found

Prioritizing what's actually exploitable, not what merely exists.

A list of 500 findings is not security. It is a backlog with a security label on it. Every scanner that ships will happily hand you that list, because raising a finding is cheap and the volume looks like thoroughness. But a queue nobody can work is a queue nobody trusts, and the only question that actually moves risk is the one most tools never answer: of these 500, which can an attacker reach and exploit right now?

The difference between a backlog and a worklist is a sequence of filters, each one throwing away findings that look scary but do not survive scrutiny. Three filters do most of the work: is the vulnerable code or dependency actually reached, was the issue proven rather than guessed, and is it on a list of things attackers are using in the wild. Stack them and 500 becomes roughly a dozen.

01Found is a claim, reachable is a fact

Most findings are reports about code that exists, not code that runs. A vulnerable function in a library you imported but never call is a finding in every SCA tool and a non-event for an attacker. Reachability analysis asks the harder question: is the vulnerable code path imported, and is there an execution route that gets to the sink? A dependency that sits in your lockfile but is never loaded does not move the risk needle, no matter how severe its CVE.

This is also where DAST and SAST stop being separate reports and start being one answer. Static analysis can say a sink exists in the source; dynamic testing can say the running application actually drove that sink with a request. When both agree, reachability is not a hypothesis - it is a path you can name. apPosture keeps these signals correlated into a single posture so the same root cause is one unit of work, not five duplicate tickets across five scanners.

02The funnel: 500 raw to about 12 worth doing

Prioritization is subtraction. Each stage removes findings that cannot survive the next test, and what falls out the bottom is the short list a team can actually clear. The numbers below are illustrative of the shape, not a benchmark - the point is the order of magnitude the filters remove.

raw findings ████████████████████████ 500 everything every scanner reported after dedup ███████████████ 310 one root cause = one finding reachable code ███████ 140 imported and on a real path proof-confirmed ██ 34 in-band / differential / arithmetic + KEV / known-exploited 12 fix these first
Each stage is a test a finding has to pass, not a score it gets nudged by. The dozen at the bottom are reachable, proven and actively exploited in the wild.

Notice that the steepest drops are the honest ones. Dedup collapses the same issue reported by multiple sources. Reachability removes the imported-but-cold code. And the proof stage - not severity, not a CVSS string - is what separates a real exploit from a theoretical one.

03Proof is what survives the reachability filter

Reachability tells you an attacker can get to the sink. It does not tell you the sink gives anything up. Those are two separate facts, and collapsing them is how reports get inflated. apPosture confirms an exploit with one of three evidence classes, each of which is a statement about the response rather than an inference about the code.

OracleWhat it confirmsExample
In-bandThe response carries data it should not - another tenant's record, a file's contents, a leaked secret./orders/1002 returns user B's order to user A.
DifferentialTwo requests that should behave identically diverge in a way only the vulnerability explains.A true vs false SQL condition flips the row count.
ArithmeticA benign computed marker returns evaluated, proving code ran without running anything dangerous.7919 * 7907 returns 62615533 from a template engine.

The arithmetic oracle is the cleanest illustration of the principle. If an expression context returns 62615533 for the input 7919*7907, the server evaluated it, and that is proof of server-side execution demonstrated with a multiplication - not a shell command, not a JNDI lookup, not a gadget chain. We keep every probe SAFE and non-destructive on purpose: proof of capability with zero blast radius is the only kind of proof you can run against a live target you do not own the right to break.

04KEV is the last cut, and it is a brutal one

After reachability and proof, the remaining findings are all real. The last filter is about attacker behavior, not your application: is this vulnerability one that is being actively exploited in the wild? The Known Exploited Vulnerabilities catalog turns "could be attacked" into "is being attacked right now elsewhere," and that is the strongest reason to move a fix to the top of the queue today rather than this quarter.

3
independent filters: reach, proof, KEV
0
findings raised on heuristic alone
1
posture - deduped across all scanners

05The funnel is also the gate

The same logic that orders a worklist can guard a pipeline. A CI gate that fails on raw finding count is the gate teams learn to bypass; a gate that fails on reachable, proof-confirmed, known-exploited findings is one they respect, because every block points at something a reviewer can verify. apPosture's gate fails closed - if it cannot be evaluated the build fails and is audited rather than passing silently - and it runs fully self-hosted, so the funnel works the same in an air-gapped network as it does anywhere else.

Reachable beats found is not a softer standard than other scanners use. It is a harder one. It costs us findings a louder tool would gladly report, and we accept that cost because a dozen items every one of which survives an audit is worth more than five hundred a reviewer stops trusting at the first false positive.

Evidence over heuristicsMonitor → Block: rolling out a gate without slowing teamsIaC-grounded threat modelingAir-gapped AppSec with no phone-homeOne platform vs three toolsOWASP Top 10 2025: what actually changed
See it on your own app →