Critical
NW-2026-001
CVSS 9.8
SQL injection in the order-search endpoint
CWE
CWE-89 — Improper Neutralisation of Special Elements used in an SQL Command
Location
POST /api/v2/orders/search — filter.reference parameter
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Description
The order-search endpoint concatenates the filter.reference value directly into a SQL statement. An unauthenticated request can therefore alter the query, read arbitrary tables in the application database, and — because the database user holds write permissions the application never uses — modify them.
Steps to reproduce
01Send a baseline request with {"filter":{"reference":"NW-1001"}} and record the response time and body.
02Replace the value with NW-1001' AND SLEEP(4)-- . The response is consistently delayed by ~4 seconds, confirming the injection point and that it is time-based blind.
03Confirm data reach with a UNION payload enumerating information_schema.tables; the response body returns table names from the application schema.
04Enumerate customers row count to establish impact. Stop there — no customer rows were retrieved beyond a single count, per the rules of engagement.
Evidence
Request/response pairs for steps 1–3, Burp Suite item IDs 4412–4419, captured 14 July 2026 11:42 IST. Evidence redacted in this specimen.
Business impact
The database user has SELECT, INSERT, UPDATE and DELETE on every application table. A remote, unauthenticated attacker can read the full customer table (name, email, phone, delivery address, order history — approximately 84,000 records in the test dataset) and can modify order and pricing records. This is a reportable personal-data breach under the DPDP Act.
Remediation
01Replace string concatenation with parameterised queries or the ORM's bound-parameter API across the entire OrderSearchRepository class, not only the reported parameter.
02Reduce the application database user to the minimum grants the application actually uses. It does not need DELETE on customers.
03Add a regression test that submits the proof-of-concept payload and asserts a 400 response.
04Review application logs for the same payload shape from before the test window to establish whether this was already being exploited.
Retest result
Closed. Re-tested 29 July 2026: the endpoint now uses bound parameters, the payload returns HTTP 400, and the database grants were reduced. Verified against all four steps above.
High
NW-2026-002
CVSS 8.1
Broken object-level authorisation on the invoice API
CWE
CWE-639 — Authorisation Bypass Through User-Controlled Key (IDOR / BOLA)
Location
GET and PATCH /api/v2/invoices/{invoiceId}
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
Description
The invoice endpoints authenticate the caller but never check that the requested invoice belongs to them. Any authenticated customer can read and modify any other customer's invoice by changing the identifier in the URL. Identifiers are sequential integers, so the whole set is trivially enumerable.
Steps to reproduce
01Authenticate as test account alpha@example.test and note an owned invoice, /api/v2/invoices/50231.
02Request /api/v2/invoices/50230 with the same session. The API returns a full invoice belonging to a different customer, including their name, billing address, line items and GSTIN.
03Issue PATCH /api/v2/invoices/50230 changing billingAddress. The change is accepted and persists.
04Increment and decrement the identifier to confirm the range is enumerable; 40 sequential identifiers were sampled and 40 returned other customers' data.
Evidence
Two authenticated sessions, side-by-side responses for steps 2 and 3. Test accounts were provisioned by the client; no production account was used.
Business impact
Any registered customer — registration is open and free — can enumerate and read every invoice in the system, and can alter billing details on invoices they do not own. This exposes personal and tax data at scale and allows financial-record tampering. Broken access control is the number-one category in the OWASP Top 10 for exactly this reason.
Remediation
01Enforce ownership server-side in the data layer: scope every invoice query by the authenticated principal, so an unowned identifier returns 404 rather than the object.
02Do not rely on the interface hiding the identifier. Hiding a link is not access control.
03Replace sequential integer identifiers with unguessable identifiers as defence in depth — but only after the ownership check is in place, never instead of it.
04Add authorisation tests to CI covering every object-scoped endpoint, asserting a 404 for a foreign identifier.
Retest result
Closed. Re-tested 29 July 2026: foreign identifiers now return HTTP 404 on both GET and PATCH, verified across 40 sampled identifiers and both test accounts.
Medium
NW-2026-003
CVSS 5.3
Missing security headers across the application
CWE
CWE-693 — Protection Mechanism Failure
Location
All responses from app.northwind-retail.test
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Description
The application returns no Content-Security-Policy, no Strict-Transport-Security, no X-Content-Type-Options and no Referrer-Policy. None of these is exploitable on its own; together they remove the browser-side controls that would blunt an XSS, a downgrade attempt or referrer leakage.
Steps to reproduce
01Request any application URL and inspect the response headers.
02Confirm the absence of Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options and Referrer-Policy.
03Confirm that a plain HTTP request to the host is answered rather than redirected, and that no HSTS policy is subsequently set.
Evidence
Full response-header capture for six representative routes.
Business impact
Raises the impact of any future cross-site scripting finding from contained to severe, permits an on-path downgrade to HTTP on a first visit, and leaks full URLs (including any identifier in a path) to third-party sites through the referrer.
Remediation
01Set Content-Security-Policy with a default-src 'self' baseline and an explicit allow-list. Deploy in report-only mode first and read the reports before enforcing.
02Set Strict-Transport-Security: max-age=31536000; includeSubDomains once HTTPS is confirmed on every subdomain.
03Set X-Content-Type-Options: nosniff and Referrer-Policy: strict-origin-when-cross-origin.
04Redirect all HTTP to HTTPS at the edge.
Retest result
Closed. Re-tested 29 July 2026: all four headers present on every sampled route; CSP is enforcing, HTTP redirects to HTTPS.
Low
NW-2026-004
CVSS 3.7
Framework version and stack trace disclosure on error
CWE
CWE-200 — Exposure of Sensitive Information to an Unauthorised Actor
Location
Error responses application-wide; Server and X-Powered-By headers
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
Description
Unhandled errors return a full stack trace including absolute file paths, internal class names and the framework version. The same version is advertised in response headers on every request.
Steps to reproduce
01Submit a malformed JSON body to any API route.
02Observe an HTTP 500 with a stack trace naming internal paths and the framework version.
03Confirm the version is independently disclosed in the X-Powered-By response header.
Evidence
Two 500 responses with traces, plus a header capture.
Business impact
No direct compromise. It shortens an attacker's reconnaissance: the exact framework version maps straight to known CVEs, and internal paths inform later path-traversal or deserialisation attempts. Rated Low on its own, but it is the phase-two enabler for several higher findings.
Remediation
01Disable debug output in production; return a generic error body with a correlation identifier and log the trace server-side.
02Remove or overwrite X-Powered-By and the verbose Server header at the reverse proxy.
Retest result
Open — accepted risk. Re-tested 29 July 2026: generic error bodies are now returned, but X-Powered-By is still present on responses from the legacy reporting service. The client has accepted this pending that service's decommission in Q4.