Reporting
6 min read
Writing a penetration test report engineers will act on
A report sorted by CVSS and delivered on a Friday afternoon has done half the job. What decides whether anything gets fixed is whether an engineer can reproduce the finding in ten minutes and knows exactly which change makes it go away. That is a writing problem more than a testing one.
Written by the Head of Application Security
A report that lists thirty findings, sorts them by score and lands in an inbox on a Friday afternoon has done half the job. The testing was probably fine. The question is whether anything changed ninety days later, and the honest answer is often that the top three were fixed and the rest were still open at the next assessment.
The reason is rarely that the engineers did not care. It is that the report was written for the person who commissioned it rather than for the person who has to open a pull request against a codebase they know far better than the tester does.
Write the finding for the engineer, not the buyer
The engineer needs four things and does not much care about the rest: where it is, what an attacker gets, how to watch it happen locally, and what the fixed state looks like. Everything else is context. We put the exact request or command in the finding with the relevant parameter marked, and we name the file, endpoint or configuration key that has to change. Advice such as validate all user input is not remediation guidance, it is a category name. If we cannot describe the specific change, we have not finished analysing the finding.
Reproduction steps are the most valuable part
A finding that cannot be reproduced gets argued about instead of fixed. We hold every reproduction in a report to the same standard.
- It names the exact host, endpoint and account role used, because the same request from a different role often behaves differently.
- It includes the raw request and response, trimmed to what matters, rather than a screenshot of a proxy window.
- It states the preconditions honestly, including whether the tester began with valid credentials or a particular feature flag enabled.
- It ends with the observable result, so the engineer knows what success looks like when they try it themselves.
CVSS is an input, not the priority order
A CVSS base score describes a vulnerability in the abstract. It does not know that the affected service sits on an isolated management network, or that the medium severity SSRF happens to live in the one component that can reach an internal metadata endpoint. We publish the score because customers, regulators and insurers ask for it, and we publish our own priority order next to it with the reasoning written out. Where the two disagree, that disagreement is the most useful paragraph in the report, and we say so plainly.
One finding, one root cause
Reporting the same missing authorisation check as fourteen separate findings, one per endpoint, inflates the count and hides the fix. Group them, describe the pattern once, list the affected endpoints as evidence, and the team gets one piece of work instead of fourteen tickets that will be closed individually and reappear after the next release. The inverse matters too: bundling three unrelated issues into one finding because they were discovered in the same feature makes them impossible to track as they are remediated at different speeds.
If the reader cannot tell which single change makes the finding go away, the finding is not finished.
The summary has a different reader
The person deciding whether to fund remediation reads two pages and stops. Those two pages should answer what an attacker could realistically achieve, which business processes are exposed, and what the three most important decisions are. No tool names, no port numbers, and no severity distribution chart that shows twelve mediums without saying what they add up to. Done properly, the summary and the technical body describe the same engagement at two altitudes, and neither is a compressed version of the other.
Write for the retest before it happens
Every finding should be written so that somebody other than the original tester can verify the fix. That means the reproduction steps double as the retest procedure and the remediation section states an observable end state rather than an intention. We also record what we tried that did not work, so the next assessment does not spend a day re establishing that the file upload handler is genuinely restrictive. The measure of a report is not its length or its finding count; it is how much of the reader's remaining work it has already done, and that is the standard we hold our own drafts to before anything is delivered.
Written by the Head of Application Security at Nullpath Security. Engagement detail in these notes is anonymised and published only where it cannot identify a client.