What a penetration test report should contain
A penetration test is only as useful as the report that comes out of it. Here is what a report should contain, and how to tell a genuine test from an exported scanner run.
Written by a Security Consultant at Infolocklabs
Organisations commission penetration tests for two reasons: to find out where they are exposed, and to satisfy someone who has asked for evidence. Both purposes are served by the same thing, which is a report that a reader can act on. A surprising number of reports serve neither.
The tell: findings without reproduction steps
The clearest signal that a report came from a tool rather than a tester is a finding that describes a class of vulnerability rather than an instance of one. "The application may be vulnerable to SQL injection" is a scanner hypothesis. "Submitting the payload below in the orderId parameter of POST /api/orders/search returns the contents of the users table, evidenced in the screenshot" is a finding.
Every finding should be reproducible by your own engineers from what the report says. If it is not, nobody can verify the fix.
What a finding should carry
- Title and location. The specific endpoint, parameter, host or configuration item.
- Reproduction steps. Precise enough to reproduce without contacting the tester.
- Evidence. Request and response, screenshot, or command output, redacted where necessary.
- Severity, with the rating explained. A CVSS vector is fine, but the report should say why the environmental factors were scored the way they were.
- Business impact. What an attacker gains. "Information disclosure" is a category; "read access to all customer records including phone numbers" is an impact.
- Remediation. Specific to your stack, not a link to a generic guidance page.
Severity should reflect exploitability, not just category
An unauthenticated remote code execution and a missing security header are not usefully compared by category. Severity should account for whether authentication is required, whether the affected function is exposed externally, what the vulnerability actually reaches, and what compensating controls exist.
A report that rates twelve findings as High because the scanner did is not prioritisation, and it will cause the genuinely urgent one to be worked in the wrong order.
Scope must be stated plainly
A report should state what was tested, what was excluded, when testing occurred, from what perspective, and what credentials were provided. This matters twice over: it tells you what assurance you actually have, and it stops a report being presented later as covering something it never touched.
"No critical findings" means very little without knowing that the test was unauthenticated, ran for two days, and excluded the payment service.
Critical findings should not wait for the report
If a tester finds an unauthenticated path to customer data on day one, you should hear about it on day one. Any engagement should define an out-of-band escalation route before it starts, and the final report should note when critical findings were communicated.
Retesting closes the loop
A test that ends at the report tells you what was wrong at a point in time. A retest after remediation tells you what is fixed. Ask whether retesting is included, how long the window is, and whether the retest produces an updated report you can share externally.
Two questions worth asking before you commission
First: how much of the testing is manual? Automated scanning has its place, but business-logic flaws, authorisation gaps and chained attacks are found by people.
Second: can you see a redacted sample report? The structure of a report tells you more about the engagement than the proposal does.