Home
VAPT Web Application PentestAPI PentestMobile App PentestInfrastructure PentestAI & LLM PentestOT / ICS PentestIoT PentestPenetration TestingAll VAPT services
Red Team Red Team EngagementAdversary SimulationAssumed BreachPurple TeamingSocial Engineering
Sectors Banking & Financial ServicesGovernment & Public SectorHealthcareOil, Gas & EnergyAviation & LogisticsRetail & E-commerceManufacturing & IndustryTelecommunicationsTechnology & SaaS
CompanyResourcesBlogFree Consultation

What an API pentest report must contain

An API pentest report is evidence, not a list. Each finding must carry the request, the response, a CVSS score and a retest record, or the report cannot be acted on.

Joel Aviad OssiJoel Aviad OssiRed Team Lead, RedTeam Security
8 min read
A layered stack of structured document cards arranged at a slight angle, each card showing evidence fields in blue and red, connected by fine lines forming a chain from the top card to the bottom.

Key takeaways

  • Every finding entry in an API pentest report must carry six fields: endpoint, OWASP category, raw request, response, CVSS score and remediation note.
  • A JWT token finding is not complete without the decoded payload showing which claims are absent or incorrectly set.
  • Rate limit evidence must show the full response sequence across the test run, not just an assertion that no 429 appeared.
  • A closed finding is not closed until the report carries a before-and-after HTTP pair with the retest date.
  • A draft that assigns severity without a CVSS vector, or marks a finding closed without retest evidence, should be returned before sign-off.

What the report has to prove

An API pentest report serves two audiences. The team fixing the code needs a reproducible description of each flaw: the exact request, the response that confirms it, and a note on the control that prevents it. The person signing off the engagement needs a record that can answer a regulatory audit: what was tested, what was found, what was fixed and when. A report that serves one and not the other will fail both.

NIST SP 800-115 describes technical security testing as a process that must produce findings traceable from the test method to the evidence. For API testing, every finding is a chain: the endpoint that was targeted, the class of weakness that applies, the exchange that proved it, and the fix that closes it.

The five phases below show where in an API pentest each part of the report is built. The scope and testing phases define what can appear as a finding. The documentation and retest phases are where the evidence standard applies. A report that UAE regulators examine as evidence must hold up at every phase.

The report structure also sets the terms for the retest. A finding documented without an endpoint reference cannot be retested systematically, because the team fixing the code may address the symptom while the original path remains open. Everything in the report flows from the finding entry: a gap there propagates into the remediation tracking, the retest record and the final sign-off.

The five phases of an API pentest. The findings and retest phases carry the evidence standard that makes the report usable.

The six layers every finding carries

A finding that names a vulnerability without showing the evidence is a claim. The OWASP API Security Top 10 maps each class of API weakness to an identifier the reader can look up independently, and CVSS translates the technical finding into a severity the fixing team can prioritise. Neither means anything without the underlying evidence.

The six fields are the minimum. The endpoint tells the reviewer what was targeted. The OWASP category and CWE reference map the weakness to published research. The raw request shows exactly what the tester sent. The response proves the flaw fired. The CVSS v3.1 vector and score let the reader verify the severity independently. The remediation note names the control, not the symptom.

The example below shows all six fields for a Broken Object Level Authorization (BOLA) finding. BOLA sits at the top of the OWASP API Security list and endpoint inventory work is what identifies which endpoints carry this exposure. Each field is on its own line so the reviewer can check them independently.

The CVSS vector is the field most often approximated rather than calculated. The score for a BOLA finding changes with the data exposed: a 7.5 reflects high confidentiality impact on a record the caller has no business reading. If the same endpoint also allows writing to records the caller does not own, the integrity sub-score changes and the overall score rises. A flat 'High' without the vector leaves the reader unable to verify that assessment.

Worked finding: BOLA on the invoice endpoint
Endpoint:    GET /api/v1/invoices/{id}
Category:    OWASP API1:2023 Broken Object Level Authorization
CWE:         CWE-639 Authorization Bypass Through User-Controlled Key

Request:
GET /api/v1/invoices/9471 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.<token-for-user-b>

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

{
  "id": 9471,
  "owner": "[email protected]",
  "amount": 14800.00,
  "status": "unpaid"
}

CVSS v3.1:   7.5 (High) AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Remediation: Enforce object ownership inside the data layer. The controller
             must verify the authenticated user owns the requested record
             before returning it. An index on (owner_id, invoice_id) prevents
             the query succeeding for a mismatched owner.

Token findings and the JWT evidence block

Tokens that grant access without expiring, or that carry no audience restriction, are a standing exposure, not a point-in-time one. A finding of this class must show the decoded payload, not just a prose description, because the reviewer needs to confirm which claims are absent and what the token actually grants. Text that says the token does not expire, without showing the payload, is not evidence.

The example below shows a JWT with no exp claim and no aud claim. The token and rate limit controls the pentest must evidence depend on these fields being correct. A missing exp leaves the token valid indefinitely after a session ends. A missing aud means the token can be replayed against any service that trusts the same signing key.

A token with no expiry claim remains valid after a session ends, after a user's role changes and after a password reset. The remediation for a missing aud claim is validation on receipt: the service must reject any token whose audience field does not match its own service identifier, so a token issued for one microservice cannot be accepted by another.

JWT finding: absent expiry and audience claims
JWT header (decoded):
{
  "alg": "HS256",
  "typ": "JWT"
}

JWT payload (decoded):
{
  "sub": "user-b",
  "role": "viewer",
  "iat": 1729900000
}

Missing claims:
  exp   Token does not expire. Valid indefinitely after session end.
  aud   No audience restriction. Accepted by any service on the same key.

Category:  OWASP API2:2023 Broken Authentication
CWE:       CWE-613 Insufficient Session Expiration
CVSS v3.1: 6.5 (Medium) AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Remediation: Set exp to the session lifetime, typically 15 to 60 minutes.
             Set aud to the specific service identifier this token is
             issued for and validate it on receipt.

Rate limit findings: the response sequence that proves it

Rate limit findings are confirmed by showing the response sequence, not by asserting its absence. A finding that states no rate limiting was observed, without the exchange log, gives the reviewer nothing to verify. The sequence must show at minimum three representative exchanges from the test run: an early success, a mid-sequence success and the final request that should have been throttled. Where the gateway is the layer under test, the exchange must be captured at that layer specifically.

The example below shows an authentication endpoint that returned 200 on 100 sequential requests. No 429 appeared and no Retry-After header was set. The finding maps to OWASP API4:2023 and CWE-307. Without the sequence log the reviewer cannot distinguish no rate limiting from a limit that the tester's tooling did not trigger.

The remediation for absent rate limiting at authentication depends on the layer. If the gateway sits in front of the service, the counter belongs at the gateway, keyed on the source IP and the target account separately. A single global counter throttles the wrong caller. The report must name the layer where the control is missing and the layer where the fix belongs, because they are not always the same.

Rate limit finding: 100 authentication attempts, all 200
# Request 1 of 100
POST /api/v1/auth/token HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"username":"[email protected]","password":"Password1"}

HTTP/1.1 200 OK
{"token":"eyJ..."}

# Request 2 of 100
POST /api/v1/auth/token HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"username":"[email protected]","password":"Password2"}

HTTP/1.1 200 OK
{"token":"eyJ..."}

# Request 100 of 100 (no throttle applied)
POST /api/v1/auth/token HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"username":"[email protected]","password":"Password100"}

HTTP/1.1 200 OK
{"token":"eyJ..."}

Finding:    100 sequential authentication requests all returned 200 OK.
            No 429 response, no Retry-After header, no account lockout.
            Credential stuffing is unrestricted on this endpoint.

Category:   OWASP API4:2023 Unrestricted Resource Consumption
CWE:        CWE-307 Improper Restriction of Excessive Authentication Attempts
CVSS v3.1:  7.5 (High) AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Remediation: Apply a sliding window counter at the gateway keyed on source IP
             and target account separately. Return 429 with Retry-After after
             five failures within any 10-minute window.

The retest record: before and after

A finding marked closed without a retest record is a claim that the fix worked. The retest record is what turns that claim into evidence: the identical request sent to the patched system, with the response that confirms the control now fires. Without it, neither the reviewer nor an auditor can tell whether the fix addresses the root cause or only changes the surface response.

The before-and-after pair below reuses the BOLA exchange from the finding anatomy section: the same endpoint, the same token, the same resource identifier. The only change is that the fix is in place. The 403 response and body both confirm the access check now runs before the query executes. The retest entry in the report must carry the date the patched build was tested alongside the exchange.

Some retests expose a second issue: the fix closes the original flaw but introduces a new behaviour, such as a 500 rather than a 403. The retest record must capture the actual response, not the expected one. A 500 on a resource the caller does not own passes the access control test but raises a separate finding. Record what the patched system returns, not what it should return.

Before fix: BOLA confirmed
GET /api/v1/invoices/9471 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token-for-user-b>

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

{"id":9471,"owner":"[email protected]","amount":14800.00,"status":"unpaid"}
After fix: access denied
GET /api/v1/invoices/9471 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token-for-user-b>

HTTP/1.1 403 Forbidden
Content-Type: application/json

{"error":"Access denied"}
Four-step retest sequence. Step one: tester sends the original BOLA request to the API. Step two: API returns 200 OK with the victim record, confirming the flaw before the fix. Step three: tester sends the identical request after the fix is deployed.
The same request before and after the fix demonstrates the control works. Both exchanges must appear in the retest record.

What to reject in a draft report

Review every draft API pentest report before sign-off. Some patterns justify returning it. A severity label without a CVSS vector cannot be verified independently: the reviewer has no way to tell whether the score reflects the actual exploitability or was assigned by convention. A finding description that cites no OWASP category or CWE reference cannot be mapped to a remediation pattern without additional research.

These checks apply to any test that produces a finding report. A web application pentest report uses the same six-layer format, though it has no JWT payload requirement. A general penetration testing report uses CVSS and CWE references in the same way. Where the API is operated by a third party, the authorisation and scoping considerations change, but the evidence format does not: the BOLA finding looks identical whether the API is yours or your supplier's. Returning a draft that fails these checks before sign-off costs less than a remediation tracking process built on incomplete evidence.

The table below lists the most frequent failures and what good looks like. Each row maps to one of the evidence blocks above, so a reviewer working through the report knows exactly what to check and what to ask for when the standard is not met.

Common draft failures and the standard each must meet before sign-off.
What you see in the draftWhy it failsWhat good looks like
Finding with no endpoint referenceCannot be reproduced or retested without knowing what was calledFull URL with method and version, e.g. GET /api/v2/invoices/{id}
Severity label with no CVSS vectorPriority cannot be verified independentlyCVSS v3.1 vector string and numeric score, e.g. 7.5 High AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Closed finding with no retest evidenceNo proof the fix addresses the root causeBefore-and-after HTTP pair with the retest date
JWT finding without decoded payloadReviewer cannot confirm which claims are absent or incorrectDecoded header and payload showing the missing fields explicitly
Rate limit finding without response sequenceCannot distinguish no limit from a limit the tester did not triggerThree or more exchanges across the test run showing 200 responses where a 429 was expected
Remediation note that names no mechanismDeveloper cannot act on it without additional researchNamed control at the right layer, e.g. object ownership check in the query layer

API pentest report standards in the UAE

CBUAE's Open Finance Framework and DESC's Cyber Risk Management Standard both ask for security testing that produces evidence a reviewer can verify. That means the report structure above is not a matter of style: a finding entry without a CVSS score, a raw request or a retest record cannot answer a regulatory examination, because there is nothing to examine.

In Abu Dhabi, ADHICS requires that healthcare system security assessments produce evidence of remediation. A report that records a finding as closed without the before-and-after request pair fails that standard by omission. ADHICS applies to any system handling patient data under the Abu Dhabi Department of Health, which includes digital health platforms and the APIs they expose to third-party integrators.

In Dubai, entities operating under DESC's supply-chain security rules must demonstrate that third-party API integrations have been tested and that defects have been remediated to a verifiable standard. The retest record is what makes remediation verifiable. Entities supplying Dubai Government must meet the same standard, so the evidence format applies to the supplier as well as the client commissioning the test.

Federal entities under the UAE IAS must retain evidence of testing and remediation for each cycle. What the CBUAE, DESC and NESA frameworks share is an expectation that test output is reproducible evidence, not a summary document. The six-layer finding format and the before-and-after retest record are the shape that evidence takes, and a report that omits either cannot satisfy these frameworks, however thorough the underlying testing was.

Frequently asked questions

What is an API pentest report?

An API pentest report is the evidence record produced at the end of an API security assessment. It documents each finding with the technical evidence that confirms it, a severity score, a recommended fix and, once remediation is complete, a retest record showing the control now works. The report is used both by the development team fixing the code and by reviewers, auditors and regulators assessing whether the testing was adequate.

What should every finding in an API pentest report include?

Each finding entry must carry the endpoint that was targeted, an OWASP API Security category and CWE reference, the raw HTTP request that confirmed the flaw, the response that proved it fired, a CVSS v3.1 vector and score, and a remediation note naming the control at the right layer. A finding that omits any of these cannot be reproduced, prioritised reliably or retested.

How does an API pentest report differ from a web application pentest report?

Both share the same six-layer finding format and the same CVSS severity standard. API pentest reports have specific evidence requirements for token findings, which must show the decoded JWT payload with the absent or incorrect claims named, and for rate limit findings, which must show the response sequence across the full test run. A web application report typically does not need either of these in this form.

What is Broken Object Level Authorization and how should it appear in a report?

Broken Object Level Authorization, OWASP API1:2023, is a flaw where an API returns a resource owned by one user to a different authenticated user because it checks only that the caller is authenticated, not that they own the record they requested. In a report it must appear with the endpoint, the OWASP identifier, CWE-639, the raw request showing the caller's token and the target resource identifier, the 200 response with the victim's data, the CVSS score and the fix.

What CVSS score is typical for a BOLA finding?

A BOLA finding with network access, low complexity, low privilege and no user interaction scores 7.5 High under CVSS v3.1 when the exposed data is confidential. The vector AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N reflects that: exploitable remotely, requires only a valid account, exposes the full record of another user. The score drops if the exposed data is not sensitive, and rises if the finding also allows modification of records the caller does not own.

What does a retest record need to show?

A retest record must carry the identical request used in the original finding, sent to the patched build, with the response confirming the control now fires. For a BOLA finding that means the same endpoint, the same token and the same resource identifier, returning 403 rather than 200. The retest date must be recorded so the reviewer can confirm the patched build was available at that point.

How should JWT token findings be documented in an API pentest report?

A JWT token finding must show the decoded header and payload, not only a prose description. The reviewer must see exactly which claims are absent or incorrectly set. A finding citing a missing exp claim should show the payload with no exp field present. A finding about an overly broad aud claim should show the actual value. Without the decoded payload the reviewer cannot confirm the finding or assess the full scope of the exposure.

What should I reject in a draft API pentest report?

Return a draft that assigns severity without a CVSS vector, marks a finding closed without a before-and-after HTTP exchange, describes a JWT flaw without the decoded payload, documents a rate limit failure without the response sequence, or names no endpoint for a finding. Any of these make the report impossible to verify, retest or submit to an auditor.

Why do API pentest reports reference both OWASP categories and CWE identifiers?

OWASP API Security categories describe the class of business logic or design flaw at the API layer. CWE identifiers map the same finding to the underlying software weakness, which is the reference developers use when searching for remediation patterns and which automated tooling often reports. Using both lets the reviewer cross-reference the finding against published research without depending on the tester's prose description alone.

How does a rate limit finding differ from a denial of service finding?

A rate limit finding documents that the API does not enforce a consumption limit on a sensitive operation, typically authentication or resource creation, leaving it open to credential stuffing or automated abuse. A denial of service finding documents that the API can be made unavailable by a volume of requests. The two are related but distinct: absent rate limits on authentication are a credential exposure risk even when the service remains fully available.

The engagements this applies to

API Pentest

Object and function level authorisation, tokens, rate limits

Joel Aviad Ossi, Red Team Lead at RedTeam Security
Joel Aviad OssiRed Team Lead, RedTeam Security

Joel Aviad Ossi is Red Team Lead at RedTeam Security, the Dubai-licensed trading brand of WebSec FZCO. He scopes and runs objective-based engagements across the UAE.

Let's talk about your security

Tell us the objective you want tested. We will come back with a scope, a timeline and a quote, under NDA from the first conversation.

Email [email protected]
IFZA Business Park, Building A2
Nadd Hessa, Dubai Silicon Oasis
Dubai, United Arab Emirates