Triaging Scanner Output: A Finding Is Not a Vulnerability
An automated scanner does not hand you vulnerabilities; it hands you hypotheses. Triage is what closes the gap: verification, context, exploitability and impact. This is the order I work through when I sit down in front of a scan report, and the traps I most often have to avoid.
Scope note
Every example in this article is generalised. No configuration, version, address or topology detail of my own infrastructure is disclosed; the goal is to convey a methodology, not to point at any target.
The difference between a finding and a vulnerability
The line a scanner produces is an observation: a signature matched, a header was absent, a response differed from the expected one. A vulnerability is something much narrower — a condition that a specific threat actor, in a specific context, can actually use to produce measurable impact.
The gap between the two consists of three questions: is it true (is the observation real), is it reachable (can an attacker get there), and is it useful (do they gain anything once they do). If you cannot answer yes to all three, what you have is a note, not a vulnerability.
A scanner is fast and thorough, but context-free. The human supplies the context — that is the whole of triage.
The triage pipeline: six steps
- Reproduce. Repeat the finding by hand, without the scanner. Look at the raw request/response pair yourself. A finding that cannot be reproduced is not up for discussion; the first cut happens here.
- Add context. What asset is affected? What data does it hold? Who can reach it? Does it require authentication? The same technical finding means entirely different things on a static brochure site and on a payments console.
- Test exploitability. Within your authorised scope, build the minimum viable proof of concept. The point is not to cause damage but to put evidence behind the sentence "this actually works".
- Write the impact. Which of confidentiality, integrity and availability is affected, and how much? Be concrete: "this data can be read without authentication". "Poses a security risk" is not an impact statement.
- Assign severity. A CVSS base score gives you a shared language, but stays incomplete without environmental and temporal metrics. And severity is not the same as priority: a low-severity finding you can close in five minutes comes before a three-month re-architecture.
- Recommend a fix, then verify it. Write a concrete, actionable remediation and retest with the same steps once it ships. Triage without closure verification is unfinished.
The number one source of false positives: version matching
Most of the noise in scan reports comes from a single pattern: the scanner reads the version a service advertises, pulls the CVE list for that version, and lists all of it as findings. That is not evidence — it is a guess.
The most common breaking point is backporting. Enterprise distributions keep the package version number fixed and backport the security patch. The service still advertises an old version string while the flaw has been closed. The version the scanner sees and the reality of the running code are not the same thing.
Before I act on a version-derived finding, I check, in order:
- Does the distribution's security tracker show a patch for the package, and in which package version?
- Is the flaw in a module or build option that is actually in use?
- Is the vulnerable code path reachable in this configuration?
- Are the preconditions met (authentication, a particular feature enabled)?
The same logic applies to dependency scanners: a package appearing in the dependency tree does not mean the vulnerable function is ever called. An alert without reachability analysis does little except occupy space in the remediation queue.
Common finding classes
The table below summarises the headings I see most often in scan reports and the decisive question I ask during triage.
| Finding | Decisive question | Typical outcome |
|---|---|---|
| CVE list derived from a version banner | Was the patch backported; is the vulnerable code path in use? | Usually a false positive |
| Missing security header | Is there a session, identity or user input on the page; which concrete attack would the header have stopped? | Usually informational |
| Weak TLS configuration | Can the weak parameter actually be negotiated, or is it merely listed? | Low / informational |
| Directory listing enabled | Does the listed content include anything that should not be reachable? | Real, depending on context |
| Reflected parameter / possible XSS | In which context is it reflected, what output encoding applies, does it actually execute? | Must be verified |
| Exposed admin or backup file | Is the content sensitive; is there authentication? | Usually real |
One caveat: "informational" does not mean "unimportant". Three findings with no impact on their own can chain into a genuine attack path. Triage means reading findings together, not one by one.
What scanners cannot see
False positives are annoying; false negatives are dangerous. The areas where automated tooling is structurally weak are quite predictable:
- Authorisation logic. Deciding whether an object can be reached with another user's identity requires knowing what the correct answer should have been. A scanner does not know that.
- Business logic. Step skipping, negative quantities, race conditions, price and discount manipulation — all require understanding the application's rules.
- Multi-step flows. Stateful operations fall outside single-request scanning.
- Chaining. Paths that emerge from combining low-severity findings do not, by definition, correspond to a single signature.
The practical conclusion: use scanning as an inventory and scoping tool, and spend the real effort on authorisation and business logic.
Reducing noise at the source
- Keep a baseline. Review the diff against the previous scan rather than the whole report. A newly appearing finding is more informative than a thousand repeated lines.
- Write the scope down. Which assets are in, which are out. An out-of-scope finding, however correct, is not the output of that engagement.
- Scan authenticated. An unauthenticated scan only ever sees the outer shell of an application.
- Record decisions with their reasoning. Write down why each finding was closed. Otherwise the same finding gets re-litigated on every scan.
Writing the report: a finding without impact is not a report
Whether a report sent to a bug bounty programme or an engineering team gets accepted largely comes down to this: can the recipient reproduce the issue on their own from what you wrote, and can they see the impact?
- A one-sentence summary: what, where, and what results from it.
- Numbered, complete reproduction steps; raw request and response.
- An impact section: which data, at which privilege level, reachable by whom.
- Preconditions and required user interaction, stated honestly.
- A recommended fix.
- Scope and authorisation statement; the time window tested.
Most rejected reports are rejected not because they are wrong but because the impact was never written. Instead of reporting a "missing header", producing a proof of concept that shows which concrete attack that missing header enables turns the same observation into a reportable finding.
Summary
A scanner is a tool for narrowing the search space; it is not the decision maker. What turns a list of findings into a list of vulnerabilities is sitting in front of each line and asking: is it true, is it reachable, is it useful.
The biggest return on that discipline is where a security team's time goes: closing the three lines that are genuinely exploitable instead of managing a hundred lines of noise. Report quality comes from the same place — evidence and impact before assertion.