Penetration Testing Report Writing: From Findings to Actionable Deliverables

The test is only half the engagement. A penetration test that discovers a critical SQL injection vulnerability and delivers a PDF that says "SQL injection found on /search endpoint — fix it" has largely failed. The finding was real; the report didn't do it justice. The developer who receives it doesn't know how to reproduce it, doesn't understand the business impact, and doesn't know whether the ORM migration or parameterized queries is the right fix for their stack.

Good pentest reports get findings fixed. Bad ones get filed. The difference is specificity, context, and actionable remediation — not volume or technical complexity. This guide covers what a professional pentest report should contain, how to structure findings so developers can act on them, and how to write executive summaries that resonate with decision-makers who don't read the technical appendix.

Report Structure: What Goes Where

A complete pentest report has six sections. Their order matters: executives read the front; developers read the middle; compliance auditors check the back.

  1. Cover page and metadata — client name, scope, test dates, assessor, report version, classification
  2. Executive summary — high-level findings, business impact, risk posture, key recommendations (1-2 pages max)
  3. Scope and methodology — what was tested, what was excluded, testing approach, tools used
  4. Findings summary — risk distribution table, findings indexed by severity
  5. Technical findings — detailed write-up per vulnerability, in severity order
  6. Appendices — raw tool output, screenshots, payload lists, methodology references

Don't mix these sections. The executive summary should never contain curl commands. The technical section should never contain business impact statements written for a non-technical audience. Different readers need different things from the same document.

The Executive Summary: Write for the CISO, Not the Developer

The executive summary is the most-read and least-written section of most pentest reports. It should answer three questions for a decision-maker who will not read the technical section:

  1. What is the overall security posture — how much risk did we find?
  2. What is the worst thing that could happen if we don't fix this?
  3. What are the top 3-5 things we should fix first, and roughly how hard are they?

Avoid technical jargon in this section. "SQL injection in the /api/users endpoint" becomes "an attacker who finds the user search feature can extract the entire user database, including password hashes." The business impact — not the vulnerability class — is what gets budget approved for remediation.

WEAK:
"Three critical vulnerabilities were identified including SQL injection,
broken access control, and sensitive data exposure."

STRONG:
"Testing identified three critical vulnerabilities. The most serious
allows any anonymous visitor to extract the complete user database —
400,000 accounts — in under 30 seconds using freely available tools.
A second flaw allows any authenticated customer to access other
customers' order history and financial data. These issues require
immediate remediation; estimated developer effort is 2-4 hours each."

Findings Format: The Five-Part Structure

Every technical finding should have the same structure. Consistency is not bureaucracy — it lets developers process a 40-finding report without recalibrating their mental model for each finding. The five parts:

1. Finding Title and Metadata

Title:        SQL Injection — User Search Endpoint
Severity:     Critical
CVSS Score:   9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
Affected URL: https://app.example.com/api/v1/users/search
Parameter:    q (GET)
CWE:          CWE-89: SQL Injection
OWASP:        A03:2021 – Injection

2. Description

Explain what the vulnerability is — not just its name. A developer who understands the root cause can fix it correctly and recognize the same pattern elsewhere. Keep this to 2-4 sentences: what the vulnerable behavior is, why it exists (the root cause), and what class of attack it enables.

The user search endpoint at /api/v1/users/search constructs a SQL
query by directly interpolating the 'q' parameter value into a WHERE
clause without parameterization. An attacker can modify the query
structure by injecting SQL syntax, enabling unauthorized read access
to any table in the database, including extraction of password hashes,
session tokens, and PII.

3. Evidence and Reproduction Steps

This is the section developers will spend the most time reading. It must be specific enough to reproduce exactly. Include the full request, the response that demonstrates impact, and a step-by-step walkthrough:

Step 1: Send the following request (unauthenticated):

GET /api/v1/users/search?q=test%27%20OR%201%3D1-- HTTP/1.1
Host: app.example.com

Step 2: Observe that the response contains user records for all users:

HTTP/1.1 200 OK
Content-Type: application/json

{"users": [{"id": 1, "email": "admin@example.com", "role": "admin"},
           {"id": 2, "email": "user@example.com", "role": "user"}, ...]}

Step 3: Extract database schema using UNION-based injection:

GET /api/v1/users/search?q=test%27+UNION+SELECT+table_name,null+FROM+
information_schema.tables-- HTTP/1.1

[Screenshot attached — full database table listing returned]

4. Impact

State what an attacker can actually do — specifically, in this application, with this data. Generic impact statements are useless. "Could lead to data breach" tells the developer nothing. "Allows extraction of the users table containing 400,000 email addresses and bcrypt-hashed passwords, the orders table containing payment card metadata, and administrative credentials" tells them exactly what's at stake.

5. Remediation

The remediation section should be specific to the stack, not generic. "Use parameterized queries" is correct but unhelpful without knowing what language and ORM the team is using. Give them the right code, not the right principle:

VULNERABLE (current code):
$query = "SELECT * FROM users WHERE email LIKE '%" . $search . "%'";

REMEDIATED (parameterized):
$stmt = $pdo->prepare("SELECT * FROM users WHERE email LIKE ?");
$stmt->execute(['%' . $search . '%']);

If using an ORM (Laravel Eloquent):
User::where('email', 'like', '%' . $search . '%')->get();
// Eloquent parameterizes this automatically

Include the fix effort estimate: "This fix requires changing 2-3 lines in UserController.php and should take less than 30 minutes including testing." This helps prioritization — a critical vulnerability that takes 20 minutes to fix gets fixed; one framed as a "major architectural change" often doesn't.

Severity and CVSS Scoring

CVSS (Common Vulnerability Scoring System) v3.1 is the standard for vulnerability severity scoring. It produces a 0-10 base score based on attack complexity, required privileges, user interaction, and the confidentiality, integrity, and availability impact.

CVSS v3.1 Score Ranges:
- Critical:  9.0 - 10.0
- High:      7.0 - 8.9
- Medium:    4.0 - 6.9
- Low:       0.1 - 3.9
- None:      0.0

Key CVSS base metrics:
AV (Attack Vector):  Network/Adjacent/Local/Physical
AC (Attack Complexity): Low/High
PR (Privileges Required): None/Low/High
UI (User Interaction): None/Required
S (Scope): Unchanged/Changed (can it affect other components?)
C/I/A (Impact): None/Low/High

CVSS has well-known limitations. A CVSS 9.8 SQL injection in a dev environment behind a VPN is less urgent than a CVSS 6.5 IDOR in production exposing financial records. Use CVSS as a starting point but apply contextual risk adjustment: factor in the sensitivity of the data, the exposure of the endpoint, whether the vulnerability is exploited in the wild, and the difficulty of exploitation in your specific environment.

When to Override CVSS with Contextual Risk

Add a separate "Contextual Risk" field when the CVSS base score doesn't reflect actual business risk:

  • Downgrade: CVSS 8.5 XSS stored in an admin panel accessible only by 3 internal admins → contextual risk: Medium
  • Upgrade: CVSS 5.0 IDOR in a healthcare application exposing diagnosis codes → contextual risk: Critical (regulatory + reputational)
  • Upgrade: CVSS 6.1 reflected XSS where the application is targeted by phishing campaigns → contextual risk: High

Writing for Different Audiences in the Same Report

A good pentest report is actually two documents in one. Structure it so each audience can navigate to what they need:

For Executives and CISOs

  • Executive summary (1-2 pages) — business impact language, no technical jargon
  • Risk distribution chart — how many Critical/High/Medium/Low findings
  • Top 3-5 recommendations — prioritized by risk × remediation effort
  • Comparison to prior assessments if applicable — trend line matters

For Developers and Security Engineers

  • Technical findings section — all five parts, stack-specific remediation
  • Proof-of-concept code and reproduction steps
  • Reference links to CWE, OWASP, CVE where applicable
  • Tool output in appendices if they want to dig deeper

For Compliance and Audit

  • Scope statement — what was tested, what was out of scope, why
  • Methodology section — testing approach references (OWASP Testing Guide, PTES)
  • Testing dates and tester credentials/certifications
  • Attestation statement if required

Common Report Writing Mistakes

Informational Findings That Add Noise

Not everything that looks like a vulnerability belongs in a pentest report as a finding. Version disclosure, missing security headers on low-value endpoints, and self-signed certificates on internal services are often better handled as a note in the methodology section than as numbered findings. Thirty findings where eight are genuinely actionable and twenty-two are "nice to have" dilutes the signal.

Missing Evidence

Pentest findings without evidence are unverifiable claims. Every critical and high finding must have a screenshot or request/response pair that proves it. "We believe SQL injection may be present" is not a finding — it's a hypothesis. Don't report what you couldn't prove.

Generic Remediation

"Implement input validation and output encoding" is not remediation guidance. It tells a developer to do something they already know they should be doing, without telling them where or how. Specific remediation — the exact file, the correct function call in their framework, the configuration flag to flip — gets fixed. Generic remediation gets forwarded to the backlog.

Inflating Severity for Effect

Every finding rated Critical means fewer of them get triaged seriously. If everything is urgent, nothing is. Reserve Critical for findings with direct, high-impact exploitation paths that require no user interaction and no prior authentication. Misrepresenting a Medium finding as Critical damages credibility and leads to triage fatigue.

Retesting and Verification

A pentest report is a living document until all findings are resolved. Structure the findings to make retest tracking straightforward:

Finding ID:   VULN-001
Title:        SQL Injection — User Search
Status:       Open → In Remediation → Fixed → Verified

Verification:
Date retested: 2026-07-15
Tester:       [assessor]
Result:       FIXED — parameterized queries confirmed via testing
              and code review of commit a3b2c1d

Offer a complimentary verification retest window as part of the engagement — typically 30-60 days after report delivery. Verification is not a new assessment; it confirms the specific findings from the report are remediated. This creates a complete engagement lifecycle and gives clients evidence for compliance purposes.

Pentest Report Checklist

  • Executive summary is jargon-free and answers: risk level, worst-case impact, and top priorities
  • Every finding has: title, severity, CVSS score, affected URL/parameter, description, evidence, impact, and remediation
  • Remediation is stack-specific — correct language and framework, not just the vulnerability class
  • Every Critical and High finding has reproducible evidence (request/response or screenshot)
  • CVSS scores are calculated correctly and contextual risk adjustments are noted
  • Scope section clearly states what was tested and what was excluded
  • Report does not include unverified hypotheses as findings
  • Severity distribution is calibrated — not everything is Critical
  • Finding IDs are stable for retest tracking
  • Appendices contain raw tool output referenced from findings
  • Report includes effort estimates for remediation where possible
  • Classification and handling instructions are on every page

Ironimo generates structured scan reports in the same format professional pentesters use — each finding includes the affected URL, request evidence, impact description, and stack-specific remediation guidance your developers can act on immediately.

Run Ironimo against your application and get a developer-ready report in minutes, not days.

Start free scan
← Back to blog