Web Application & API Penetration Test
Northbridge Commerce — fictional demonstration organisation
Read this before using the sample
This is a realistic demonstration of the Breachroad reporting standard. The organisation, systems, identifiers, requests and findings are fictional. No client engagement, compromise or production data is represented here.
Report contents
- 01Executive summary
- 02Engagement record
- 03Risk and findings
- 04Validated attack path
- 05Remediation roadmap
- 06Detailed findings
- 07Coverage and limitations
- 08Retest plan
- 09Method and references
Executive summary
Determine whether an authenticated customer could cross tenant boundaries, manipulate payment state or retain access after an account-security event.
The assessment confirmed two high-risk weaknesses. A low-privilege account could access an invoice belonging to another tenant, while an unsigned payment webhook could alter invoice state. Neither issue required administrative access.
The combined path creates confidentiality and fraud exposure: customer and invoice data can cross an isolation boundary, then a trusted payment state can be changed outside the intended provider flow.
MFA was enforced for administrators, direct administrative endpoints rejected customer roles, upload validation blocked active content, and no SQL injection or remote code execution was confirmed.
Engagement record
Tested systems
app.example.test · api.example.test · auth.example.test
Explicit exclusions
Denial of service, social engineering, third-party payment provider infrastructure and access to non-test customer data.
Test model
Grey-box assessment using two isolated customer tenants and one support test role. Production-like configuration; synthetic records only.
Point-in-time limitations
A penetration test samples agreed attack paths during a defined window. It is not a guarantee that every vulnerability is identified or that the environment remains unchanged.
Risk and findings
| ID | Finding | CVSS | Severity | Status |
|---|---|---|---|---|
| BR-01 | Cross-tenant invoice access through missing object-level authorisation | 7.1 | HIGH | OPEN |
| BR-02 | Unsigned payment webhook accepted by business logic | 7.5 | HIGH | OPEN |
| BR-03 | Refresh token remains valid after password reset | 6.5 | MEDIUM | OPEN |
| BR-04 | Account-recovery endpoint reveals registered email addresses | 5.3 | MEDIUM | OPEN |
| BR-05 | Content Security Policy permits unsafe inline script execution | 3.1 | LOW | OPEN |
| BR-06 | Security events lack tenant-boundary context | — | INFO | OPEN |
Validated attack path
The material risk is clearer as one sequence than as isolated scanner alerts.
- STEP 01Compromised low-privilege customer account
- STEP 02Predictable invoice reference obtained from normal workflow
- STEP 03Object ownership is not enforced by the API
- STEP 04Cross-tenant invoice data is returned
- STEP 05Unsigned webhook changes a trusted payment state
Remediation roadmap
0–7 days
Enforce object-level authorisation on invoice reads. Reject every webhook without a valid signature before parsing business data. Review logs for cross-tenant invoice references and unsigned webhook traffic.
Within 30 days
Centralise authorisation policy, add negative tenant-isolation tests, rotate webhook secrets, revoke active sessions after password and recovery events, and rate-limit recovery enumeration.
Within 90 days
Introduce security regression tests into CI, monitor tenant-boundary denials and webhook verification failures, and repeat targeted testing after material identity or payment changes.
Detailed findings
Cross-tenant invoice access through missing object-level authorisation
High — one authenticated request and a valid-format identifier
High — disclosure of customer and billing data across a tenant boundary
API / Product
- Root cause
- The endpoint verifies the session and invoice identifier, but does not bind the object to the authenticated tenant.
- Sanitised evidence
- GET /v1/invoices/inv_demo_9d3 with <TENANT_A_TOKEN> returned HTTP 200 and tenant_id: tenant_demo_b.
- Remediation
- Enforce tenant ownership in the data-access layer, deny by default, and add negative tests for every object reference and role.
- Retest acceptance criteria
- Tenant A receives 404/403 for every Tenant B invoice route; no metadata differs; regression tests cover list, detail, PDF and export.
- References
- CWE-639 · OWASP API1:2023 · WSTG-ATHZ-04
Unsigned payment webhook accepted by business logic
High — public endpoint and no valid provider signature required
High — an attacker can create a trusted paid state outside the payment provider flow
Payments / Backend
- Root cause
- Signature verification runs only when the signature header is present; missing input falls through to processing.
- Sanitised evidence
- POST /v1/webhooks/payment without X-Payment-Signature returned HTTP 202 and changed demo invoice status to paid.
- Remediation
- Verify the raw request body before parsing, reject missing/invalid signatures, enforce timestamp tolerance and idempotency, and rotate the secret.
- Retest acceptance criteria
- Missing, invalid, replayed and expired signatures all fail before state change; valid signed fixtures pass once.
- References
- CWE-345 · OWASP API10:2023 · WSTG-BUSL-02
Refresh token remains valid after password reset
Medium — requires possession of a previously issued refresh token
High — an existing session can survive a security-driven credential reset
Identity
- Root cause
- Password reset changes the credential but does not increment the session generation or revoke refresh-token families.
- Sanitised evidence
- A token issued before reset returned a new access token after reset completion and user notification.
- Remediation
- Revoke all refresh-token families on password reset and recovery; offer visible session management and security-event telemetry.
- Retest acceptance criteria
- Every pre-reset refresh token fails after reset; active sessions are revoked and the event is logged with account and device context.
- References
- CWE-613 · OWASP ASVS V3 · WSTG-SESS-06
Account-recovery endpoint reveals registered email addresses
High — remote, unauthenticated and automatable
Low to medium — improves phishing, credential-stuffing and privacy targeting
Identity / UX
- Root cause
- Response body and timing differ between registered and unknown addresses.
- Sanitised evidence
- Known address returned recovery channel metadata; unknown address returned a distinct code and response length.
- Remediation
- Return one generic response, equalise processing, rate-limit by account and network signals, and alert on enumeration patterns.
- Retest acceptance criteria
- Known and unknown accounts have equivalent status, body shape and practical timing distribution.
- References
- CWE-204 · OWASP ASVS V2 · WSTG-IDNT-04
Content Security Policy permits unsafe inline script execution
Low — no independent injection point was confirmed
Low in isolation — defence in depth is reduced if a future injection is introduced
Frontend
- Root cause
- The production policy includes unsafe-inline without nonces or hashes.
- Sanitised evidence
- Content-Security-Policy contains script-src self unsafe-inline; sampled pages expose no nonce.
- Remediation
- Move inline code to static assets, adopt nonces or hashes and deploy the stricter policy in report-only mode first.
- Retest acceptance criteria
- No unsafe-inline remains; normal flows work under enforced CSP and violations are monitored.
- References
- CWE-693 · OWASP Secure Headers Project
Security events lack tenant-boundary context
Operational gap
Slower investigation and weaker evidence during suspected cross-tenant activity
Platform / SOC
- Root cause
- Application logs capture route and user but omit resolved tenant, object owner and authorisation decision.
- Sanitised evidence
- Denied and successful invoice events could not be correlated to both authenticated and object-owner tenant IDs.
- Remediation
- Log actor tenant, target tenant, object type, decision and trace ID without sensitive payloads; alert on mismatch attempts.
- Retest acceptance criteria
- A controlled denied request produces a complete, searchable event and an agreed detection signal.
- References
- OWASP ASVS V7 · NIST SP 800-92
Coverage matrix
| Area | Result | Notes |
|---|---|---|
| Authentication & recovery | PARTIAL | Session lifecycle issue confirmed; MFA and reset-token single use worked. |
| Authorisation & tenancy | FAIL | Object-level authorisation failure confirmed on invoice retrieval. |
| Business logic & payments | FAIL | Unsigned webhook accepted by application logic. |
| Input handling | PASS | No exploitable injection confirmed in tested paths. |
| Files & integrations | PASS | Upload and callback restrictions held in sampled cases. |
| Logging & detection | PARTIAL | Events existed, but lacked tenant-boundary and signature-failure context. |
Retest plan
A retest should use the original requests and two isolated tenants. Closure requires server-side ownership validation on every invoice route, fail-closed signature verification before webhook processing, session revocation tests and regression coverage. A code change alone is not closure.
Method and references
CVSS v3.1 + business context
Severity combines demonstrated business impact and exploit conditions. CVSS v3.1 is included as a transparent technical reference, not as a replacement for environmental risk. Every numeric score is paired with its vector.
OWASP · PTES · NIST
The sample structure follows OWASP WSTG reporting guidance, PTES reporting criteria and NIST SP 800-115. Finding identifiers, evidence, affected components, remediation and retest criteria remain traceable throughout the document.