A penetration test is only as useful as its report. The test itself takes days; the report is what the engineering team works from for months, what the auditor reads, and what management uses to decide whether the money was well spent. Yet most reports we are asked to review fall into one of two failures: a raw scanner export with a cover page, or a narrative so hedged that nobody can tell what to fix first.
This is the structure we hold our own reports to, and the one we suggest you write into your next request for proposal.
1. Scope, as tested — not as planned
The first page should state exactly what was in scope and what was actually exercised: hostnames, IP ranges, application versions, user roles, environments (production, staging, a replica), and the dates. If a system was in scope but could not be tested — an endpoint was down, credentials never arrived, a WAF blocked the tester and was not adjusted — the report must say so. Otherwise a clean result for that system is a false assurance.
Ask for: the list of tested assets with the date each was touched, and a list of exclusions with reasons.
2. Methodology and standard
Name the methodology and stick to it. For web applications that is usually the OWASP Web Security Testing Guide, with the Application Security Verification Standard for depth; for APIs, the OWASP API Security Top 10 and the same ASVS chapters; for infrastructure, PTES or the NIST 800-115 phases. The value is not the acronym — it is that a named checklist lets a reader see what was not found, not only what was.
A short table mapping the standard's sections to "tested / not applicable / out of scope" is the single most useful page many reports lack.
3. Executive summary that an executive can act on
One page. What was tested, the overall risk in one sentence, the count of findings by severity, and the two or three things that must happen this quarter. No screenshots, no payloads. If the reader stops here, they should know whether to worry and who to call.
4. Findings, one per page, in a fixed shape
Every finding needs the same fields, in the same order, so that a hundred findings can be triaged in an afternoon:
| Field | What it must contain |
|---|---|
| Title | The weakness, not the tool alert ("Order lookup exposes other customers' orders", not "IDOR found") |
| Severity | A rating and the rationale, using a published scheme (CVSS v4 base score with the vector string, or the OWASP risk rating) |
| Affected assets | Exact URLs, parameters, hosts, versions — enough to reproduce without asking |
| Reproduction | Step-by-step, with the request and response, redacted only where necessary |
| Impact | What an attacker actually gets: which data, which accounts, which systems — in the customer's terms |
| Root cause | The missing control, not the symptom ("authorisation is checked by the client only") |
| Remediation | A specific fix and, where relevant, an interim mitigation; a link to a standard, not a paragraph copied from it |
| Evidence | Screenshots or captures that prove the finding on the tested system |
Two things separate a report you can act on from one you cannot. First, severity must be argued, not asserted: "High" means nothing without the vector. Second, root cause must be named: five findings that share one cause are one fix, and the report should say so.
5. Chains and business impact
Individual findings understate risk when they combine. A low-severity information disclosure plus a medium-severity access-control flaw can equal full account takeover. A good report includes at least one attack chain written as a story: where the tester started, what each step yielded, and where it ended. That narrative is what makes a board understand the number in the summary.
6. What was tried and did not work
A tester who spent a day on the authentication flow and found nothing has produced evidence. It belongs in the report as a short section of negative results: which attack classes were attempted against which components. Without it, the customer cannot distinguish "secure" from "not looked at".
7. Retest terms
State whether a retest is included, its window, and what it covers. A report without a retest path leaves findings in limbo. The retest report should reference the original finding IDs and give each a status: fixed, partially fixed, not fixed, or accepted as a risk with a named owner.
8. Appendices that save time
Scanner outputs, full request logs, tooling and versions used, and a machine-readable export of the findings (CSV or JSON) so the engineering team can import them into their tracker rather than retype them. The machine-readable version is not a nicety; it is what makes the report get worked.
The questions to ask before you sign
- Will the report state what could not be tested, and why?
- Which standard will the coverage be mapped to, and will I see that map?
- Does every finding carry a scored severity with its vector, a root cause, and a reproduction?
- Is there a retest, and how are statuses reported?
- Will I receive the findings in a form my tracker can import?
A vendor who answers all five without hesitation is describing a report you can act on. If the answer to any of them is "we can add that", ask to see a redacted sample first.