A representative deliverable illustrating Dual Legion's reporting standard. All targets, hosts, and data shown are fictional and for demonstration only.
Confidential — do not distributeThis document contains sensitive information about the security posture of the systems in scope. It is intended solely for the named recipient and authorised staff.
| Version | Date | Author | Notes |
|---|---|---|---|
| 0.1 | 10 Aug 2026 | Lead Consultant | Internal draft — findings under peer review |
| 0.9 | 12 Aug 2026 | QA / Technical Review | Evidence verified, CVSS ratified |
| 1.0 | 13 Aug 2026 | Engagement Lead | Final 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.
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.
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.
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.
| Asset | Type | Environment | Access provided |
|---|---|---|---|
portal.northwind-sample.test | Customer web portal | Staging (prod parity) | 2× standard customer accounts |
api.northwind-sample.test | REST API (v2) | Staging (prod parity) | API keys for both test users |
portal.northwind-sample.test/admin | Staff console | Staging | Unauthenticated only (black-box) |
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.
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.
| Phase | Activities | Layer |
|---|---|---|
| Reconnaissance & mapping | Endpoint enumeration, parameter discovery, auth-flow mapping, technology fingerprinting | AI-assisted |
| Automated discovery | Authenticated crawling, injection/mis-config sweeps, access-control matrix generation | AI-assisted |
| Manual exploitation | Authorization testing (IDOR/BOLA), injection confirmation, SSRF, business-logic abuse, exploit chaining | Human operator |
| Validation | Hand-reproduction of every candidate finding, false-positive elimination, CVSS ratification | Human operator |
| Reporting | Impact narrative, engineer-ready remediation, peer & QA review | Human 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.
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.
| ID | Finding | Severity | CVSS | Status |
|---|---|---|---|---|
| DL-2026-001 | SQL injection in reporting date filter | Critical | 9.1 | Open |
| DL-2026-002 | Broken object-level authorization on documents | High | 8.1 | Open |
| DL-2026-003 | Server-side request forgery in import | High | 7.7 | Open |
| DL-2026-004 | JWT accepted without signature verification | Medium | 6.5 | Open |
| DL-2026-005 | Stored XSS in support-ticket subject | Medium | 5.4 | Open |
| DL-2026-006 | Missing security headers | Low | 3.1 | Open |
| DL-2026-007 | Verbose error messages disclose stack traces | Info | 0.0 | Open |
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.
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.
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.
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.
...&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.
/api/v2/reports/export with a valid date range through an intercepting proxy.' AND '1'='1 to the to parameter — the report returns normally.' AND '1'='2 — the report returns empty, proving the injection.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.
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.
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.
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.
10480).10481, 10482…) with user A's token.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.
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.
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.
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.
source_url pointing to an internal address.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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
HTTP/1.1 500 Internal Server Error
{"error":"SequelizeDatabaseError",
"stack":"at /srv/app/services/report.js:88 ...",
"framework":"Express 4.x / Node 20"}
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.
Beyond fixing the individual findings, the following themes would raise Northwind's baseline and prevent recurrence.
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.
| Priority | Findings | Suggested SLA |
|---|---|---|
| Critical | DL-2026-001 | Immediate — within 7 days |
| High | DL-2026-002, DL-2026-003 | Within 14 days |
| Medium | DL-2026-004, DL-2026-005 | Within 30 days |
| Low / Info | DL-2026-006, DL-2026-007 | Next release cycle |
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.
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.
| Rating | CVSS band | Meaning |
|---|---|---|
| Critical | 9.0 – 10.0 | Immediate, severe impact. Exploitable with little effort; direct data or system compromise. |
| High | 7.0 – 8.9 | Significant impact; exploitable by a motivated attacker. Prioritise. |
| Medium | 4.0 – 6.9 | Moderate impact or requires specific conditions to exploit. |
| Low | 0.1 – 3.9 | Limited impact; defence-in-depth or hardening. |
| Info | 0.0 | No direct security impact; noted for awareness. |
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.