Skip to content
Parlix
All posts

Verifying a vulnerability before reporting it

A candidate finding and a vulnerability are different objects. Here's the verification stage that separates them, and why it deletes more than it keeps.

The Parlix Team 3 min read
engineering verification

Most of the Parlix pipeline exists to produce candidates. The last part exists to destroy them. This post is about that second half — what verification actually does, and why it throws away more than it keeps.

A candidate is not a finding

When the search stage flags a flow, what it has produced is a hypothesis: given this path from this entry point to this sink, an attacker who controls the input should be able to achieve X. That hypothesis is plausible by construction — it survived flow extraction, stack inspection, the audit and validation. It is also, quite often, wrong.

The failure modes cluster:

  • The guard is off-path. There is a check, and it protects a sibling route.
  • The sink isn’t one. A helper that looks like it executes turns out to escape first.
  • The input isn’t reachable. The entry point requires a role the attacker can’t obtain.
  • The reasoning skipped a step. The path is real but relies on a state that can’t occur.

None of these are visible from the flow alone. They only appear when something goes back and tries to build the exploit.

What verification does

Verification takes a candidate and attempts to independently reconstruct the attack, with no privileged knowledge of why the earlier stage thought it worked. It has to answer three questions in order:

  1. Can an attacker reach the entry point? Under what authentication, what role, what deployment configuration.
  2. Can they control the value that reaches the sink? Not influence it — control it, through every transformation on the way.
  3. Does reaching the sink produce the claimed effect? Given the actual library, version and configuration in this repository.

A “no” at any step deletes the candidate. There’s no partial credit and no “possible” severity, because a maybe costs the reviewer exactly as much attention as a yes and returns nothing.

candidate ──▶ reachable? ──no──▶ discard
                  │yes
                  ▼
             controllable? ──no──▶ discard
                  │yes
                  ▼
              effective? ──no──▶ discard
                  │yes
                  ▼
               finding ──▶ chaining

Then chaining changes the severity

Verified findings go to a chaining stage, and this is where the ranking usually stops matching intuition. Two findings that read as “medium” on their own — say an authenticated file-read and a predictable temporary path — compose into an unauthenticated remote code execution. Neither is interesting alone. Together they’re the reason you get paged.

Chaining is the stage that most closely mirrors how a real assessment works: nobody stops at the first bug, they ask what the first bug buys them.

The cost, honestly

Verification is the most expensive stage in the pipeline, and it exists to reduce the size of the output. That’s a strange thing to pay for, and it’s worth being direct about the trade:

  • It increases scan cost and duration.
  • It reduces the number of findings you receive.
  • It raises the share of them that are real.

We think that’s the correct trade every time, because the alternative — a longer report that nobody finishes reading — has a real-world detection rate of zero.

Curious what Parlix finds in your code?

Point it at one repository and we'll walk you through every verified finding.

Book a demo