Skip to content
bughunter.pro
/Request an audit

What does a penetration test report look like?

Nobody should buy an audit without knowing what the deliverable looks like. This page follows the exact structure of the PDF we hand over at the end of an engagement: same sections, same level of detail. Only the content differs, because it is rebuilt and anonymised here.

A report read by two people who want different things.

An audit report has two readers, and they do not open it for the same reason. Leadership wants to know what is at risk, how long they have, and where to start. The engineering team wants the exact path, the request to replay, and the line to change. A report that only speaks to one of them ends up in a drawer.

That is why the executive summary is written without jargon, with a glossary where a term cannot be avoided, and the technical detail comes after it in full, raw requests included. Both live in the same document: nobody has to ask for the long version.

Severity is not a score copied out of a tool. Every finding carries a vectorised CVSS, but the priority reflects what the flaw allows in your environment. A critical on an isolated staging box is not handled like a high on the service that carries your payments.

The eight sections, in order.

The contents page is the same on every engagement. You know where to look before you open the document.

01

Rules of engagement

The exact target, the written authorisation covering the test, the dates, the duration, the method and the tooling used. It also carries a declaration of what was touched: test accounts created and then deleted, reversible changes, third-party data masked. Nothing is left behind.

02

Executive summary

What is well protected, what is not, the main risks and the recommended order of action. Written to be read by a board without a security background, with a glossary for the terms that cannot be translated away.

03

Findings summary

The summary table: a number, a severity, the component affected, the vulnerability, the impact and the status. One page to see everything, and the way into the detail.

04

Findings in detail

One entry per flaw. Severity and vectorised CVSS, a precise description of the defect, reproduction evidence with the raw requests, demonstrated impact, exploitation prerequisites, numbered remediation and status.

05

What holds

Most reports list only problems, which paints a false picture of a system that is often sound overall. Knowing what is already solid stops you from rebuilding what did not need rebuilding.

06

Non-blocking recommendations

The hardening that does not belong in the findings list but still shrinks the surface: headers, configuration, logging, rate limiting. Kept separate so it never drowns the priorities.

07

Retest

The result of replaying the tests after your fixes, finding by finding, with the date and what was observed. This is the section that turns a list of problems into a closed file, and it arrives as version 1.1 of the report.

08

Appendices

The full requests and evidence, gathered at the back so the body of the report stays readable. Screenshots and sensitive access are kept separately and sent over an encrypted channel, never pasted into the document.

The findings summary.

A rebuilt extract. Every row points to a detailed entry in the next section of the report.

Example of a findings summary table
No.SeverityComponentVulnerabilityImpact
4.1Criticalapi.example.com/v1/orders/{id}Object-level access control missing (BOLA) on order readsAny customer's order readable from its identifier alone
4.2Highapi.example.com/v1/accountrole field accepted on write (mass assignment)A standard account promotes itself to admin in one request
4.3Highwww.example.com, password resetReset token never expiresAn intercepted link still works weeks later
4.4Mediumwww.example.com, loginNo rate limiting on authentication attemptsCredentials from public breaches replayed at scale

One finding, in full.

This is the complete entry for row 4.1 above. It is the level of detail your engineering team receives, for every flaw.

4.1 Any customer's orders readable without authorisation

Critical
Severity Critical, CVSS 3.1: 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)
Component GET /v1/orders/{id} on api.example.com
Description The API checks that the caller is authenticated, but not that the order requested belongs to them. The identifier is a sequential integer passed in the URL. An authenticated customer who swaps their own identifier for someone else's receives the whole order: name, delivery address, phone number, line items and total. The server answers 200 either way.
Reproduction
GET /v1/orders/4172 HTTP/1.1
Host: api.example.com
Authorization: Bearer <test account token>

HTTP/1.1 200 OK
{"id":4172,"customer":"test account","total":"149.90", ...}

GET /v1/orders/4173 HTTP/1.1
Host: api.example.com
Authorization: Bearer <the same token>

HTTP/1.1 200 OK
{"id":4173,"customer":"a different customer","total":"318.00", ...}
Impact Impact demonstrated on reads. Because the identifiers are sequential, enumeration is trivial and scriptable: the entire order history is retrievable from a single legitimate customer account. The data involved is personal data under the GDPR (article 4); confirmed exploitation would be a breach notifiable to the supervisory authority within 72 hours (article 33). No write was attempted.
Prerequisites A standard customer account, created freely from the site. No prior privilege escalation, no victim interaction.
Remediation
  1. Check server-side, on this route and on every route that takes an object identifier, that the object requested belongs to the session's user.
  2. Handle access control in a shared layer rather than route by route, so the omission stops being possible.
  3. Replace sequential identifiers with unguessable ones (UUID v4). Defence in depth, not a fix on its own.
  4. Audit the access logs for past enumeration against this route.
Status Fixed by the client, then verified at the retest. The retest is included in the engagement: no finding stays marked as fixed on our word alone.

What the report does not contain.

As much as what it holds, what is deliberately absent from it is part of the engagement.

  • None of your customers' real data. Evidence is truncated and masked, and extracted datasets are never copied into the document.
  • No live credentials or tokens. Anything that has to reach you goes over an encrypted channel, separately from the report. And if real account credentials have leaked and we come across them during the engagement, we flag it right away so you can change them, without waiting for delivery.
  • No padding. No raw tool output pasted in, no unverified theoretical finding added to inflate the count.
  • No circulation. The report is yours; we share it with nobody and we never name a client.

A report like this one, on your application.

Describe the perimeter and we come back with a scope and a quote. First conversation with no commitment, complete confidentiality.