CTF7
PricingFree tierFAQ Sign in

VAPT report template with a CVSS 4.0 example

A copy-ready vulnerability report template for pentests, bug bounty programs and Raw Ops competitions, a fully worked IDOR example scored with CVSS 4.0, an executive-summary template for full VAPT reports and the mistakes that get reports rejected.

A good VAPT or vulnerability report template has a clear title, a one-paragraph summary, the affected asset and scope, the vulnerability type and CWE, a severity backed by a CVSS 4.0 vector, a description, numbered steps to reproduce, a proof-of-concept request and response, business impact, specific remediation, references and a disclosure timeline.

Key takeaways

  • One report per vulnerability. Lead with impact, then prove it with steps anyone can reproduce in under five minutes.
  • Always include the full CVSS 4.0 vector string, not just a number, and justify each metric in a sentence.
  • Show the raw HTTP request and response. Redact real secrets and personal data, but keep enough to prove the bug.
  • Remediation should name the fix (for example, "enforce object-level authorization in the handler"), not just "sanitize input."
  • Most rejections come from four causes: duplicates, out-of-scope assets, no demonstrable impact and irreproducible steps.
  • Full VAPT reports add an executive summary, scope and methodology, a findings table and retest status on top of individual findings.

What goes into a vulnerability report

If you are a pentester delivering a VAPT (vulnerability assessment and penetration testing) engagement, a bug bounty hunter submitting to a program or a player in a Raw Ops competition, the reader of your report has the same three questions: Is this real? How bad is it? How do we fix it? Every section in the template exists to answer one of them. If you're coming from flag-based games, how a CTF differs from a report-based round explains the shift, and practitioners can sharpen their testing on War Zone raw targets.

SectionAnswersWhat reviewers look for
TitleWhat and whereVulnerability type + component + impact in one line
SummaryHow badTwo to four sentences a manager can read
Asset and scopeIs it ours, is it allowedExact URL, host, version, environment; confirmation it's in scope
Type and CWEWhat class of bugA specific CWE, not a vague parent category
Severity (CVSS 4.0)How bad, objectivelyFull vector string plus a rationale per metric
DescriptionWhy it happensRoot cause in plain language
Steps to reproduceIs it realNumbered, deterministic, with test accounts and preconditions
PoC request/responseIs it realRaw HTTP or script output, redacted where needed
ImpactWhy the business should careConcrete data, users or actions affected
RemediationHow to fixSpecific code or config change, plus defense in depth
ReferencesWhere to learn moreCWE, OWASP, vendor advisories
TimelineWhat happened whenDiscovery, report, triage, fix, retest, disclosure

Copy-ready vulnerability report template (Markdown)

This template works for a single finding in a pentest report, a bug bounty submission or a Raw Ops report. It's plain Markdown, so it pastes cleanly into Jira, GitHub, Confluence or whichever tool your event or program uses. Replace everything in {curly braces}.

vulnerability-report-template.md
# {Vulnerability type} in {component/endpoint} allows {impact}

| Field              | Value |
|--------------------|-------|
| Report ID          | {RPT-YYYY-NNN} |
| Reporter           | {Name / handle, contact} |
| Date submitted     | {YYYY-MM-DD} |
| Asset              | {URL / host / app + version / environment} |
| Vulnerability type | {e.g. Broken Object Level Authorization (IDOR)} |
| CWE                | {CWE-NNN: Name} |
| Severity           | {Critical / High / Medium / Low / None} |
| CVSS 4.0 score     | {x.x} |
| CVSS 4.0 vector    | {CVSS:4.0/AV:_/AC:_/AT:_/PR:_/UI:_/VC:_/VI:_/VA:_/SC:_/SI:_/SA:_} |
| Status             | {New / Triaged / Fixed / Retested} |

## 1. Summary
{2-4 sentences: what the bug is, where it is, what an attacker
can do with it and who is affected. Write this last.}

## 2. Asset and scope
- Target: {https://app.example.com/api/v2/...}
- Environment: {production / staging / competition target}
- Version / build: {if known}
- In scope because: {quote the scope line or program rule}
- Test accounts used: {attacker account, victim account}

## 3. Vulnerability type and CWE
- Class: {OWASP category, e.g. API1:2023 Broken Object Level Authorization}
- CWE: {CWE-NNN: Name} ({link})

## 4. Severity (CVSS 4.0)
Vector: {CVSS:4.0/...}
Score: {x.x} ({severity})
Rationale:
- AV:{N/A/L/P}: {why}
- AC:{L/H}: {why}
- AT:{N/P}: {why}
- PR:{N/L/H}: {why}
- UI:{N/P/A}: {why}
- VC/VI/VA:{H/L/N}: {impact on the vulnerable system}
- SC/SI/SA:{H/L/N}: {impact on other systems}

## 5. Description
{Root cause in plain language. Which check is missing or broken,
and why the application trusts attacker-controlled input.}

## 6. Steps to reproduce
Preconditions: {accounts, roles, feature flags, browser}
1. {Step}
2. {Step}
3. {Step}
Expected result: {what should happen}
Actual result: {what happens}

## 7. Proof of concept
### Request
```http
{raw HTTP request, secrets redacted}
```
### Response
```http
{raw HTTP response, trimmed, personal data masked}
```
{Optional: script, screenshot or video link}

## 8. Impact
{Concrete consequences: which data, how many records or users,
what an attacker can chain it with, regulatory exposure.}

## 9. Remediation
- Primary fix: {specific code/config change}
- Defense in depth: {logging, rate limits, tests}
- Verification: {how the team can confirm the fix}

## 10. References
- {CWE link}
- {OWASP / vendor advisory link}
- FIRST CVSS v4.0 specification: https://www.first.org/cvss/v4-0/

## 11. Timeline
| Date       | Event |
|------------|-------|
| {YYYY-MM-DD} | Vulnerability discovered |
| {YYYY-MM-DD} | Report submitted |
| {YYYY-MM-DD} | Triaged / acknowledged |
| {YYYY-MM-DD} | Fix deployed |
| {YYYY-MM-DD} | Fix retested |
| {YYYY-MM-DD} | Public disclosure (if agreed) |

Write the summary last. Once the steps, PoC and impact are down, the summary almost writes itself, and it will match what you proved instead of what you hoped to prove.

Filled example: IDOR on /api/v2/users/{id}

Here is the template filled in for a realistic finding: an insecure direct object reference (IDOR), also called broken object level authorization (BOLA). It is the first entry in the OWASP API Security Top 10 (2023). The target is fictional: shop.example.com.

# IDOR in GET /api/v2/users/{id} exposes any customer's profile and address

| Field              | Value |
|--------------------|-------|
| Report ID          | RPT-2026-014 |
| Asset              | https://shop.example.com/api/v2/users/{id} (production) |
| Vulnerability type | Broken Object Level Authorization (IDOR) |
| CWE                | CWE-639: Authorization Bypass Through User-Controlled Key |
| Severity           | High |
| CVSS 4.0 score     | 7.1 |
| CVSS 4.0 vector    | CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N |

## 1. Summary
The user profile endpoint GET /api/v2/users/{id} returns the full
profile of whatever numeric ID is requested, without checking that
it belongs to the logged-in user. Any registered customer can read
the name, email, phone number and saved addresses of every other
customer by changing the ID. IDs are sequential, so the whole user
base can be enumerated with a simple loop.

## 2. Asset and scope
- Target: https://shop.example.com/api/v2/users/{id}
- Environment: production (in scope per program rule 2.1:
  "*.example.com APIs, authenticated testing with own accounts")
- Test accounts: attacker (user id 10482), victim (user id 10483),
  both created by the reporter

## 3. Vulnerability type and CWE
- OWASP API1:2023 Broken Object Level Authorization
- CWE-639: Authorization Bypass Through User-Controlled Key

## 4. Severity (CVSS 4.0)
Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Rationale:
- AV:N  reachable over the internet
- AC:L  no special conditions; change one path parameter
- AT:N  no race, no non-default configuration required
- PR:L  any free self-registered customer account works
- UI:N  victim does nothing
- VC:H  full profile of every customer is disclosed
- VI:N  PUT/PATCH on other IDs returned 403; no write access shown
- VA:N  no availability impact
- SC/SI/SA:N  no impact beyond this application

## 5. Description
The handler loads the user record by the {id} path parameter and
returns it. It verifies that the request has a valid session token
but never compares the requested id with the session's user id.
Authentication is enforced; object-level authorization is not.

## 6. Steps to reproduce
Preconditions: two customer accounts (A = 10482, B = 10483).
1. Log in as account A and copy the Bearer token from any API call.
2. Send GET /api/v2/users/10482 with A's token. You see A's profile.
3. Send the same request with the id changed to 10483.
Expected: 403 Forbidden or 404 Not Found.
Actual: 200 OK with account B's full profile.

## 7. Proof of concept
### Request
GET /api/v2/users/10483 HTTP/2
Host: shop.example.com
Authorization: Bearer eyJhbGciOi...[redacted, account A]
Accept: application/json

### Response
HTTP/2 200 OK
Content-Type: application/json

{
  "id": 10483,
  "name": "B*** S****",
  "email": "b****@example.org",
  "phone": "+91 98*** ***12",
  "addresses": [ { "line1": "[masked]", "city": "Pune", "pin": "411***" } ],
  "created_at": "2026-09-19T10:22:41Z"
}

Enumeration check: 10 requests only (own ID plus adjacent IDs),
stopped immediately per program rules. Result: 10 of 10 returned 200.
Request log attached as evidence.

## 8. Impact
Any customer can harvest the personal data of all customers:
names, emails, phone numbers and delivery addresses. This enables
targeted phishing and fraud, and may be a notifiable personal data
breach under laws such as India's DPDP Act 2023 or the GDPR.
Sequential IDs make full enumeration trivial.

## 9. Remediation
- Primary fix: in the handler, load the record with both the path id
  and the authenticated user id (or return 404 when they differ).
  For admin roles, check an explicit permission instead.
- Better: expose GET /api/v2/users/me and drop the id parameter
  for customer-facing calls.
- Defense in depth: centralize object-level authorization in a
  policy layer; add automated tests that call every object endpoint
  with a second user's token; alert on one token reading many IDs.
- Note: switching to UUIDs makes guessing harder but is NOT a fix.
- Verification: repeat step 3; expect 403/404.

## 10. References
- https://cwe.mitre.org/data/definitions/639.html
- https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/
- https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html
- https://www.first.org/cvss/v4-0/

## 11. Timeline
| Date       | Event |
|------------|-------|
| 2026-09-19 | Discovered during authenticated API testing |
| 2026-09-19 | Report submitted |
| 2026-09-20 | Triaged, severity confirmed as High |
| 2026-09-24 | Fix deployed |
| 2026-09-25 | Fix retested: 403 returned for foreign IDs |

That vector scores 7.1 (High) in CVSS 4.0. Try it yourself in our CVSS 4.0 calculator, then change single metrics to see how sensitive the score is. With PR:N (no login needed), the same bug would score 8.7. If the tester had also shown write access with VI:H, it would reach 8.6. Each of those claims must be proven in the PoC, not assumed.

Stay inside the rules while proving impact. The example accesses one victim account the reporter owns and sends ten enumeration requests, then stops. Mass-downloading real customer data to "prove" a bug turns a valid report into a policy violation, and in many programs into a legal problem.

Scoring severity with CVSS 4.0

CVSS 4.0 was published by FIRST on 1 November 2023 as the successor to 3.1; check which version a program asks for before you score. For reports, three changes matter most:

  • Attack Requirements (AT) is new. It captures conditions outside the attacker's control, like winning a race or a non-default configuration. Don't overload Attack Complexity (AC) with them.
  • Scope is gone. Instead of S:C, impact is split into the vulnerable system (VC/VI/VA) and subsequent systems (SC/SI/SA). A stored XSS that hits users' browsers is usually low on the vulnerable system and has impact on subsequent systems.
  • Name the score type. A base-only score is CVSS-B. Adding threat metrics gives CVSS-BT, and environmental metrics give CVSS-BE or CVSS-BTE. Researchers normally report CVSS-B, and the vendor adds threat and environmental context.

Scores between versions aren't directly comparable, so re-score in 4.0 rather than converting a 3.1 number. The severity bands are the same: None 0.0, Low 0.1–3.9, Medium 4.0–6.9, High 7.0–8.9, Critical 9.0–10.0. Our CVSS 4.0 guide walks through every metric with examples.

Executive summary template for full VAPT reports

A full VAPT report bundles many findings for a client. The individual findings use the template above. The document around them needs its own structure, and the executive summary is the page leadership reads. Keep it to one page and avoid jargon.

vapt-executive-summary.md
## Executive summary

**Engagement:** {Client} commissioned {Tester/Company} to perform a
{black/gray/white-box} vulnerability assessment and penetration test of
{systems} between {start date} and {end date}.

**Scope:** {N} web applications, {N} APIs, {N} external IPs,
{mobile apps / internal network / cloud accounts}. Out of scope: {…}.

**Methodology:** Testing followed {OWASP WSTG / OWASP MASVS /
PTES / NIST SP 800-115} and combined automated scanning with manual
testing. Severity is rated with CVSS 4.0 (base score, CVSS-B).

**Overall risk:** {Critical / High / Medium / Low}

| Severity | Count | Fixed at retest |
|----------|-------|-----------------|
| Critical | {n}   | {n}             |
| High     | {n}   | {n}             |
| Medium   | {n}   | {n}             |
| Low      | {n}   | {n}             |
| Info     | {n}   | n/a             |

**Key risks (plain language):**
1. {e.g. Any logged-in customer can view other customers' personal data.}
2. {…}
3. {…}

**Strategic recommendations:**
1. {e.g. Centralize authorization checks for all API objects.}
2. {e.g. Add security test cases to the CI pipeline.}
3. {e.g. Retest all High and Critical findings within 30 days.}

**Positive observations:** {controls that worked well}

Full VAPT report structure

  1. Cover and document control: client, version, classification (confidential), distribution list, revision history.
  2. Executive summary: the template above.
  3. Scope and rules of engagement: targets, test window, source IPs, accounts provided, exclusions.
  4. Methodology and severity model: standards followed and how CVSS 4.0 was applied.
  5. Findings summary table: ID, title, severity, CVSS score, status, sorted by severity.
  6. Detailed findings: one section per finding, using the report template.
  7. Retest results: status of each finding after fixes.
  8. Appendices: tools used, raw scan output, evidence and glossary.

How to write a vulnerability report that gets accepted

1. Lead with impact

"Any customer can read every other customer's address" beats "Missing authorization check on user endpoint." Triagers skim dozens of reports a day. Make the title and the first sentence of the summary carry the business consequence.

2. Make it reproducible in five minutes

  • Number every step, and state preconditions: account type, role, feature flags, browser.
  • Include exact requests. Copy them from Burp Suite or your browser's dev tools as raw HTTP or curl.
  • Say what you expected and what actually happened.
  • If a race or timing is involved, share the script and how many attempts it takes.
  • Retest your own steps from a clean session before submitting.

3. Don't inflate severity

Over-rating is the fastest way to lose a triager's trust. Score what you demonstrated, not the theoretical worst case. Common inflation patterns:

  • Setting PR:N when the attack needs a logged-in account.
  • Claiming VI:H for a read-only IDOR because "they could probably write too."
  • Rating self-XSS, missing security headers or a version banner as High.
  • Scoring a whole chain at the highest link's severity without proving each step.

If you believe an escalation is possible but couldn't prove it within the rules, say so in the Impact section and leave the vector at what you proved.

4. One vulnerability per report, but show chains

Split unrelated bugs into separate reports so each can be tracked and fixed. When bugs chain, for example an open redirect plus an OAuth misconfiguration that leads to account takeover, write one report for the chain, explain each link and reference the individual reports.

5. Give fixes developers can act on

Name the vulnerable function or layer if you can, the correct control (parameterized queries, object-level authorization, output encoding for the right context) and how to verify the fix. Link to the relevant OWASP Cheat Sheet.

6. Handle evidence responsibly

Redact tokens, passwords and third-party personal data. Use your own test accounts wherever possible. Store evidence securely and delete it when the program or contract says to.

Common reasons vulnerability reports get rejected

RejectionWhy it happensHow to avoid it
DuplicateSomeone reported it first, or it's a known issueReport fast and precisely. Check public disclosures and the program's known-issues list.
Out of scopeAsset, subdomain or bug class excluded by the policyRe-read the scope before testing. Quote the scope line in the report.
No security impact / informativeMissing headers, version disclosure, self-XSS, logout CSRFShow a realistic attack scenario, or chain it with something that has impact.
Not reproducibleMissing preconditions, expired tokens, environment differencesRetest from a clean account. Include exact requests and timestamps.
Scanner output onlyPasted tool results with no manual verificationVerify manually and explain the exploit path.
Works as intendedDocumented or accepted behaviorRead the docs. Argue the risk if you still believe it's a flaw.
Policy violationDoS, social engineering, excessive data accessStop at the minimum proof and follow the rules of engagement.

How Raw Ops on CTF7 triages reports

Raw Ops is CTF7's "anti-CTF": there are no flags. Participants investigate a realistic target, find real-world-style vulnerabilities and submit reports much like the template above. Points come after triage, and severity is scored with CVSS 4.0. That makes it a close simulation of a VAPT engagement or a private bug bounty program, and a strong way to practice writing reports under time pressure.

Submit

Players submit a structured report: title, asset, vulnerability type, description, steps to reproduce, PoC, impact and a proposed CVSS 4.0 vector.

Validate

Triagers check scope, reproduce the steps and confirm the impact shown. Reports that can't be reproduced may be sent back for more information.

Deduplicate

Reports for the same root cause are grouped, so a bug is rewarded once rather than every time it's reported.

Score

Triagers confirm or adjust the CVSS 4.0 vector, and the score drives points. Chaining multiple weaknesses into a bigger impact is encouraged.

Exact point rules, triage windows and duplicate policies are set per event by the organizer, so read the event brief. Organizers get post-event analytics on report quality alongside solve and leaderboard data, which is useful for hiring assessments and training. If you're planning one, tell us about your event. Our explainer on what Raw Ops is and why it has no flags covers the format in depth, and hiring security talent with CTFs shows how recruiters read these reports.

Where to go next

  • Score it properly. Use the CVSS 4.0 calculator and scoring guide to justify every metric in your vector.
  • Know where reports fit. CTF vs bug bounty covers scope, legality and rewards, and how to go from flags to a first valid report.
  • Write up what you learn. The CTF writeup guide has a template for flag-based challenges, which complements this one for findings.
  • Practice under a clock. Raw Ops scores reports like these after triage, and the Raw Ops format page explains how events run.

Plan your next event with us

A free jeopardy event for up to 50 players goes live when you publish it. For flagship events, our team can build the challenges and run the managed formats: attack-defense, King of the Hill and SOC simulations.

CTF7 mascot holding a CTF7 flag