Skip to content
← All insights

Security & Quality

What a vulnerability report needs before anyone fixes it

6 min readWarmbytes Engineering

Article

The report arrives and it is good work. The findings are real, the severities are defensible, the writing is clear, and the engagement did what it was asked to do. It goes to the team, who accept it without argument.

At the next cycle most of it is still open. The few items that closed are the ones with obvious one-line fixes — a header, a cookie attribute, a version bump. Everything structural is in the same state it was in, and nobody can quite say why. The team did not dispute the findings. They were not told to ignore them. They just never had what they needed to act.

That is the common shape, and it is not a motivation problem. A report written to describe what was found and a report written to be acted on are different documents, and most engagements deliver the first while everybody assumes they commissioned the second.

What a finding has to carry

A reproduction someone can run. Not that a parameter is injectable, but the exact request, the exact input, the response that came back, and the state before and after. This is the single highest-leverage thing in a report. Most of what looks like a disagreement about severity is really "I could not make that happen", and a reproduction settles it instead of starting a correspondence that outlives everyone's interest.

The location in the team's terms, not the scanner's. A host and a path identify a URL. The person changing the code needs the handler, the shared component, the middleware. A report that stops at the URL leaves the team to rediscover that mapping for every finding, and the rediscovery is exactly where duplication hides: twenty findings against twenty endpoints are frequently one missing check in one shared function. Reported as twenty, they get twenty patches, several of which are wrong and all of which are separately reviewable.

A severity that shows its preconditions. A score is a conclusion. The useful part is the inputs: what the attacker must already have — network position inside the estate, a valid session, an authenticated privileged role — and what they get if they succeed. Two findings carrying the same number are wildly different pieces of work if one is reachable by any internet user and the other needs an administrator who is already inside. Omit the preconditions and the team either reconstructs them for every finding before it can order the work, or trusts the number and fixes the wrong thing first.

Write for the person who has to change the code

A fix direction, not a fix. The reporter usually does not know the codebase and the team does, so prescribing the patch is both presumptuous and unhelpful. What the reporter does know is which remedies close the class of defect and which merely defeat the payload that was used. "Enforce this on the server, on the authorization path" is a direction a team can implement in its own architecture. Handing over a payload and nothing else reliably produces a fix that rejects that payload and nothing else — and a second engagement that finds the same defect with different input.

A stated retest condition. A finding with no defined closure test cannot be closed, only argued about. Say what would have to be true: this reproduction, run this way, no longer reproduces. Then "fixed" is a claim with evidence behind it rather than an assertion in a status column, and the team has something to aim at that is not a vibe.

Grouping by cause, not by instance. Report structure becomes remediation structure, reliably and without anyone deciding it should. A report that enumerates instances produces a team patching instances. A report that names the shared cause and lists its instances underneath produces a team fixing the cause and verifying the instances — which is the same work, ordered correctly, and materially less of it.

One report cannot serve three readers

Most reports are asked to satisfy an auditor, an executive and an engineer at once, which is why they satisfy none of them.

The auditor needs coverage and provenance: what was in scope, what was examined, when, by whom, and what the conclusions were. The executive needs exposure in business terms and a decision to make. The engineer needs reproduction, location, preconditions and a retest condition, and has no use for the prose either of the others needs.

Written as one document, the engineering content is the part that gets compressed, because it is the least legible to whoever signs off the report. The shape that works is one body of findings with different views onto it — an executive summary that links into the findings rather than summarising them away, and per-finding detail that is allowed to be dull and specific. Which view a reader gets should be a decision, not an accident of who held the pen.

How this gets handled in practice

Where the practice is mature, the report is not really the deliverable. Findings land in the team's issue tracker as individual items, each with its reproduction attached, prioritised against everything else competing for the same sprint. The retest is contracted before the engagement starts, and a finding closes when a retest passes.

Across Pakistan and comparable markets the report usually is the deliverable, for structural reasons rather than anyone's carelessness. It is commissioned against a regulatory or partner deadline, arrives as a document attached to an email, and gets transcribed by hand into a spreadsheet that becomes the real tracking artifact. The retest is a separate engagement nobody budgeted, so it happens at the next annual cycle or not at all — and the artifact that closes the loop is a management response describing intent, not a passing test.

The addressing problem is sharper here too. The report's first reader is a regulator or a partner's assurance function, so it is written toward coverage statements and defensible process, which is a legitimate requirement that pulls directly away from reproduction detail. The engineering content survives only if somebody asks for it explicitly.

Both corrections are cheap and neither needs a bigger budget. Put the retest in the original contract, where it costs a fraction of a second engagement. And make the per-finding format an acceptance criterion of the deliverable, so reproduction steps and a retest condition are things the supplier owes rather than things a developer requests after the invoice is paid.

Before you accept the next one

Ask the supplier, before signing, to write one finding exactly the way you want all of them written: reproduction, location in your terms, preconditions behind the severity, fix direction, retest condition. Read it with the engineer who would have to act on it, and ask whether they could start on Monday.

That one sample tells you more about what the engagement will be worth than the methodology section does, and asking for it costs nothing. The suppliers who work this way will produce it immediately. The ones who cannot are telling you something useful while there is still time to act on it.

securityvulnerability-managementremediationreporting