DUAL LEGION
AI SPEED. HUMAN PRECISION.
Penetration Test Report · Sample

Web Application & API
Security Assessment

A representative deliverable illustrating Dual Legion's reporting standard. All targets, hosts, and data shown are fictional and for demonstration only.

Client
Northwind Financial (SAMPLE)
Engagement
Grey-box Web & API Pentest
Assessment window
03 – 12 Aug 2026
Report version
v1.0 — Final
Prepared by
Dual Legion Offensive Team
Classification
Confidential — Client Only
Confidential — do not distribute
DOCUMENT CONTROL

Confidentiality & handling

This document contains sensitive information about the security posture of the systems in scope. It is intended solely for the named recipient and authorised staff.

VersionDateAuthorNotes
0.110 Aug 2026Lead ConsultantInternal draft — findings under peer review
0.912 Aug 2026QA / Technical ReviewEvidence verified, CVSS ratified
1.013 Aug 2026Engagement LeadFinal issue to client

Every finding in this report was reproduced by hand before issue. Dual Legion does not ship scanner output as findings. Distribution of this document beyond the client organisation requires written consent from both parties.

CONTENTS

Table of contents

SECTION 1

Executive summary

Dual Legion was engaged to perform a grey-box penetration test of Northwind Financial's customer portal and its supporting API. The objective was to determine whether an attacker — starting from a standard, low-privilege customer account — could access other customers' data, escalate privileges, or compromise back-end systems.

The application is well built in most respects: authentication is sound, session handling is modern, and the majority of common web weaknesses were not present. However, the assessment identified a chain of authorization and injection flaws that, combined, allow a single authenticated customer to read arbitrary customer records and ultimately execute queries against the production database. This represents a material risk to customer data confidentiality and to regulatory standing.

Seven issues were confirmed in total: one Critical, two High, two Medium, one Low, and one Informational. The Critical and both High findings are exploitable by any registered user and should be prioritised for immediate remediation.

Overall risk
HIGH
Pre-remediation
Critical
1
High
2
Medium
2
Low
1
Info
1

Key business risks

The headline

A single low-privilege customer account is enough to read other customers' data and reach the production database. None of the three primary issues requires social engineering, insider access, or a chained zero-day — only a valid login and a proxy.

SECTION 2

Scope & rules of engagement

Testing was authorised in writing and constrained to the assets below. No denial-of-service testing was performed, and no destructive actions were taken against production data.

AssetTypeEnvironmentAccess provided
portal.northwind-sample.testCustomer web portalStaging (prod parity)2× standard customer accounts
api.northwind-sample.testREST API (v2)Staging (prod parity)API keys for both test users
portal.northwind-sample.test/adminStaff consoleStagingUnauthenticated only (black-box)
Engagement type
Grey-box, authenticated
Testing window
03–12 Aug 2026, 09:00–18:00 BST
Source IPs
198.51.100.20/31 (allow-listed)
Out of scope
DoS, physical, third-party SaaS, staff email

A shared Slack channel was used for real-time coordination. One issue (DL-2026-001) was disclosed early, ahead of the final report, under the 48-hour Critical disclosure SLA.

SECTION 3

Methodology

The engagement followed Dual Legion's two-layer model: broad automated discovery to map the surface quickly, followed by manual expert testing to confirm, chain, and prove impact. Findings are mapped to the OWASP Testing Guide and OWASP API Security Top 10, and severity is scored with CVSS v3.1.

PhaseActivitiesLayer
Reconnaissance & mappingEndpoint enumeration, parameter discovery, auth-flow mapping, technology fingerprintingAI-assisted
Automated discoveryAuthenticated crawling, injection/mis-config sweeps, access-control matrix generationAI-assisted
Manual exploitationAuthorization testing (IDOR/BOLA), injection confirmation, SSRF, business-logic abuse, exploit chainingHuman operator
ValidationHand-reproduction of every candidate finding, false-positive elimination, CVSS ratificationHuman operator
ReportingImpact narrative, engineer-ready remediation, peer & QA reviewHuman operator

Tooling included an intercepting proxy, custom request-tampering scripts, and manual review. A full tool list is in Appendix A. Automated output was treated as leads only — nothing reached this report without hands-on confirmation.

SECTION 4

Findings summary

Seven findings are listed below in priority order. Each links to its detailed write-up, with a CVSS v3.1 base score and the OWASP category it maps to.

IDFindingSeverityCVSSStatus
DL-2026-001SQL injection in reporting date filterCritical9.1Open
DL-2026-002Broken object-level authorization on documentsHigh8.1Open
DL-2026-003Server-side request forgery in importHigh7.7Open
DL-2026-004JWT accepted without signature verificationMedium6.5Open
DL-2026-005Stored XSS in support-ticket subjectMedium5.4Open
DL-2026-006Missing security headersLow3.1Open
DL-2026-007Verbose error messages disclose stack tracesInfo0.0Open
SECTION 5

Detailed findings

Each finding below gives the affected component, a CVSS vector, the business impact, sanitised evidence, step-by-step reproduction, and specific remediation. Evidence has been redacted where it would expose live secrets.

DL-2026-001

SQL injection in reporting date filter

Critical
CVSS v3.1
9.1 — Critical
OWASP
A03:2021 — Injection
CWE
CWE-89
Affected endpoint
GET /api/v2/reports/export
Parameter
to (date filter)
Auth required
Standard customer

Summary

The reporting export endpoint builds its SQL query by concatenating the from and to date parameters directly into the statement. The to parameter is not parameterised, allowing an authenticated user to inject arbitrary SQL. The database responds to boolean and time-based payloads, confirming an exploitable injection that yields read access to the full database.

Impact

An attacker with any customer login can extract arbitrary data from the application database — including other customers' PII, account balances, and the users table containing password hashes and password-reset tokens. This is a direct, single-step path to a large-scale data breach.

Evidence

Request — a boolean condition changes the response
GET /api/v2/reports/export?from=2026-01-01&to=2026-08-01'+AND+'1'='1 HTTP/1.1
Host: api.northwind-sample.test
Authorization: Bearer <customer-token>

-- Returns HTTP 200 with the normal report.
-- Changing the tail to  ...'+AND+'1'='2  returns an empty set,
-- confirming the condition is evaluated by the database.
Confirmation — time-based response
...&to=2026-08-01'+AND+(SELECT+1+FROM+PG_SLEEP(5))+IS+NOT+NULL--

-- Response delayed by ~5s, confirming query execution.
-- Full data extraction was demonstrated in a controlled manner
-- and shared privately with the Northwind team; payloads redacted here.

Steps to reproduce

  1. Authenticate to the API as a standard customer and capture the bearer token.
  2. Send a request to /api/v2/reports/export with a valid date range through an intercepting proxy.
  3. Append ' AND '1'='1 to the to parameter — the report returns normally.
  4. Change it to ' AND '1'='2 — the report returns empty, proving the injection.
  5. Use a time-based payload to confirm blind execution without reading data.
Remediation

Replace string concatenation with parameterised queries / prepared statements for every database call in the reporting service. Validate from and to against a strict date format server-side, and run the reporting database role with read-only, least-privilege permissions. Confirm no other endpoints share the vulnerable query builder.

References: OWASP Injection Prevention Cheat Sheet · CWE-89 · OWASP API8:2023 Security Misconfiguration.

DL-2026-002

Broken object-level authorization on documents

High
CVSS v3.1
8.1 — High
OWASP API
API1:2023 — BOLA
CWE
CWE-639
Affected endpoint
GET /api/v2/documents/{id}
Parameter
{id} (document ref)
Auth required
Standard customer

Summary

The document-retrieval endpoint checks that the caller is authenticated but does not verify that the requested document belongs to the calling user. Document identifiers are sequential integers, so any authenticated user can enumerate and download every document in the system.

Impact

Full read access to all customers' uploaded documents — bank statements, ID scans, and signed agreements. Because identifiers are sequential, the entire corpus can be harvested with a simple loop.

Evidence

Request — user A retrieves user B's document
GET /api/v2/documents/10493 HTTP/1.1
Host: api.northwind-sample.test
Authorization: Bearer <user-A-token>

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="statement-userB-jul2026.pdf"

-- Document 10493 belongs to a different customer,
-- yet is returned to user A without an authorization error.

Steps to reproduce

  1. Log in as test user A and note the ID of one of your own documents (e.g. 10480).
  2. Request neighbouring IDs (10481, 10482…) with user A's token.
  3. Observe that documents owned by other customers are returned successfully.
Remediation

Enforce an ownership check on every object access: confirm the authenticated principal owns (or is explicitly authorised for) the requested id before returning it. Prefer non-sequential, unguessable identifiers (UUIDs) as defence in depth, but do not rely on them in place of the authorization check.

References: OWASP API1:2023 BOLA · CWE-639 · OWASP Authorization Cheat Sheet.

DL-2026-003

Server-side request forgery in document import

High
CVSS v3.1
7.7 — High
OWASP
A10:2021 — SSRF
CWE
CWE-918
Affected endpoint
POST /api/v2/documents/import
Parameter
source_url
Auth required
Standard customer

Summary

The import feature fetches a document from a user-supplied URL server-side. The URL is not validated against an allow-list, so the server can be induced to make requests to internal addresses that are not reachable from the internet.

Impact

An attacker can map and reach internal-only services from the application server — including the cloud metadata endpoint, which in many configurations exposes temporary credentials. This expands the blast radius from the application to the surrounding internal network.

Evidence

Request — server fetches an internal address
POST /api/v2/documents/import HTTP/1.1
Host: api.northwind-sample.test
Authorization: Bearer <customer-token>
Content-Type: application/json

{"source_url":"http://169.254.169.254/latest/meta-data/"}

-- The response body echoes the internal metadata listing,
-- proving the server followed the attacker-controlled URL.
-- Credential paths were NOT retrieved during testing.

Steps to reproduce

  1. Call the import endpoint with a source_url pointing to an internal address.
  2. Observe that the server's response reflects content only reachable from inside the network.
  3. Confirm external URLs still work, ruling out a generic error.
Remediation

Validate source_url against a strict allow-list of permitted hosts and schemes; reject private, loopback, and link-local ranges after DNS resolution (to prevent rebinding). Disable HTTP redirects on the fetch, and block access to the cloud metadata endpoint at the network layer (e.g. IMDSv2 with hop limit 1).

References: OWASP SSRF Prevention Cheat Sheet · CWE-918.

DL-2026-004

JWT accepted without signature verification

Medium
CVSS v3.1
6.5 — Medium
OWASP
A07:2021 — Auth Failures
CWE
CWE-347
Affected endpoint
API-wide (bearer auth)
Parameter
Authorization header
Auth required
Any valid token

Summary

The API accepts JSON Web Tokens whose header specifies alg: none, and does not reject tokens with a stripped signature. An attacker who obtains any valid token structure can forge one with modified claims (for example, a different user ID) without knowing the signing key.

Impact

Identity spoofing. Combined with the sequential user IDs seen elsewhere, an attacker could craft a token asserting another user's identity. Scored Medium because the current claim set limits immediate privilege escalation, but the underlying trust failure is serious.

Evidence

Forged token — signature removed, alg downgraded
Header : {"alg":"none","typ":"JWT"}
Payload: {"sub":"1042","role":"customer","exp":...}
Signature: <omitted>

-- Request with the unsigned token returns HTTP 200
-- and serves data for sub=1042, confirming no verification.
Remediation

Reject the none algorithm outright and pin the expected algorithm server-side (e.g. RS256). Always verify the signature before reading any claim, validate exp/iat/aud, and rotate the signing key. Do not let the token header dictate the verification algorithm.

References: OWASP JWT Cheat Sheet · CWE-347.

DL-2026-005

Stored XSS in support-ticket subject

Medium
CVSS v3.1
5.4 — Medium
OWASP
A03:2021 — Injection (XSS)
CWE
CWE-79
Affected endpoint
POST /api/v2/support/tickets
Parameter
subject
Auth required
Standard customer

Summary

The ticket subject field is stored without output encoding and rendered directly into the staff support console. A script placed in the subject executes in the browser of any staff member who views the ticket queue.

Impact

A customer can run script in a staff member's authenticated session — a path to session theft or actions performed as support staff. Scored Medium because it requires a staff member to view the queue, which is a routine action.

Evidence

Stored payload (sanitised)
POST /api/v2/support/tickets
{"subject":"<img src=x onerror=CONSOLE_PoC()>","body":"..."}

-- When the staff console renders the queue, the handler fires.
-- A benign console proof-of-concept was used; no session data
-- was exfiltrated during testing.
Remediation

Contextually output-encode all user-supplied fields when rendering in the staff console, and apply a strict Content-Security-Policy that disallows inline script. Validate/normalise input on the way in as defence in depth. Audit all customer-controlled fields shown to staff, not just the subject.

References: OWASP XSS Prevention Cheat Sheet · CWE-79.

DL-2026-006

Missing security headers

Low
CVSS v3.1
3.1 — Low
OWASP
A05:2021 — Misconfiguration
CWE
CWE-693
Affected
portal.northwind-sample.test
Headers
CSP, HSTS, X-Content-Type-Options
Auth required
None

Summary

Responses from the portal omit several recommended security headers. On their own these do not create a vulnerability, but they weaken defence-in-depth and would make issues such as DL-2026-005 easier to exploit.

Evidence

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html
-- Absent: Content-Security-Policy
-- Absent: Strict-Transport-Security
-- Absent: X-Content-Type-Options: nosniff
-- Absent: Referrer-Policy
Remediation

Add Content-Security-Policy, Strict-Transport-Security (with a suitable max-age and preload), X-Content-Type-Options: nosniff, and a restrictive Referrer-Policy at the edge. Test CSP in report-only mode first to avoid breaking functionality.

References: OWASP Secure Headers Project · CWE-693.

DL-2026-007

Verbose error messages disclose stack traces

Info
CVSS v3.1
0.0 — Informational
OWASP
A05:2021 — Misconfiguration
CWE
CWE-209
Affected
api.northwind-sample.test
Trigger
Malformed request bodies
Auth required
None

Summary

Malformed requests cause the API to return full stack traces, framework versions, and internal file paths. This is not directly exploitable but hands an attacker reconnaissance that accelerates other attacks.

Evidence

HTTP/1.1 500 Internal Server Error
{"error":"SequelizeDatabaseError",
 "stack":"at /srv/app/services/report.js:88 ...",
 "framework":"Express 4.x / Node 20"}
Remediation

Return generic error responses to clients and log detail server-side only. Disable debug/verbose error output in production and set a catch-all error handler that strips stack traces.

References: OWASP Error Handling Cheat Sheet · CWE-209.

SECTION 6

Strategic recommendations

Beyond fixing the individual findings, the following themes would raise Northwind's baseline and prevent recurrence.

SECTION 7

Retest & next steps

A remediation retest is included in this engagement at no additional cost. Once fixes are deployed to staging, Dual Legion will re-test each finding and issue an updated report reflecting the new status.

PriorityFindingsSuggested SLA
CriticalDL-2026-001Immediate — within 7 days
HighDL-2026-002, DL-2026-003Within 14 days
MediumDL-2026-004, DL-2026-005Within 30 days
Low / InfoDL-2026-006, DL-2026-007Next release cycle
Included

One full retest of all findings, an updated report, and a 30-minute readout call with your engineering team to walk through fixes. Book via your engagement lead.

SECTION 8

Appendices

Appendix A — Tooling

Intercepting proxy, custom request-tampering and enumeration scripts, JWT inspection utilities, and manual browser-based testing. Automated discovery was used to surface candidates only; every reported issue was hand-verified.

Appendix B — Severity definitions

RatingCVSS bandMeaning
Critical9.0 – 10.0Immediate, severe impact. Exploitable with little effort; direct data or system compromise.
High7.0 – 8.9Significant impact; exploitable by a motivated attacker. Prioritise.
Medium4.0 – 6.9Moderate impact or requires specific conditions to exploit.
Low0.1 – 3.9Limited impact; defence-in-depth or hardening.
Info0.0No direct security impact; noted for awareness.

Appendix C — About this sample

This is a demonstration report. "Northwind Financial", all hostnames, identifiers, and evidence are fabricated to illustrate structure, tone, and depth. A real Dual Legion engagement report is scoped to your environment and contains only findings verified against your systems.

© 2026 Dual Legion · Confidential — Client Only · Sample report v1.0 Machines scan. Humans hunt.