Worked exemplar: how a finding is written up
A finding is only useful if a developer can reproduce it, a manager can rank it, and an insurer or auditor can see it was assessed. That means four things every time: what it is, how to trigger it, what it costs you, and what closes it.
Scope and method
- Target: OWASP Juice Shop, deployed locally in an isolated container.
- Access level: unauthenticated, then a self-registered standard user.
- Method: manual testing against the OWASP Web Security Testing Guide, supported by targeted tooling. Automated output is used to direct attention, never submitted as findings.
- Excluded: denial of service, social engineering, and anything destructive.
- Ratings: CVSS v3.1 base score, and the CWE the weakness belongs to.
Findings summary
| # | Finding | Severity | CVSS v3.1 | CWE |
|---|---|---|---|---|
| 1 | Authentication bypass via SQL injection in the login form | Critical | 9.8 | CWE-89 |
| 2 | Another user's basket readable by changing an identifier | High | 7.5 | CWE-639 |
| 3 | Confidential documents served from a listable directory | Medium | 5.3 | CWE-548 |
Finding 1 — Authentication bypass via SQL injection
Severity: Critical · CVSS v3.1: 9.8 · CWE-89: improper neutralisation of special elements used in an SQL command.
What it is
The login form concatenates the submitted email address directly into an SQL query. An attacker can close the string and comment out the remainder of the statement, so the password check is never evaluated. The application authenticates them as the first matching account, which is the administrator.
How to reproduce
- Open the login page as an unauthenticated visitor.
- Submit
' OR 1=1--as the email address, with any value as the password. - The session returned is an authenticated administrator session.
What it costs you
Complete compromise of the application and every account in it, reachable by an unauthenticated attacker over the internet, requiring no special knowledge and leaving little distinguishable trace in application logs. If this application processes personal information, this is the finding that turns into a breach-notification decision.
What closes it
Parameterised queries for every database call, so user input is never part of the statement text. Fix the pattern across the codebase rather than this one form, and add a regression test that submits the payload above and asserts authentication fails. An input filter that blocks quotes is not a fix and will be bypassed.
Finding 2 — Another user's basket readable by changing an identifier
Severity: High · CVSS v3.1: 7.5 · CWE-639: authorization bypass through user-controlled key.
The basket endpoint checks that the caller is logged in, but not that the basket belongs to them. Incrementing the identifier returns another customer's basket contents. The distinction matters: the application has authentication and no authorization. Closing it means the ownership check belongs in the data access layer, where every route inherits it, rather than in each handler where one omission reopens the hole. It is among the most common serious weaknesses in multi-tenant applications, and scanners do not find it — whether a given user should see a given record is a question about your business, not about the HTTP response.
Finding 3 — Confidential documents served from a listable directory
Severity: Medium · CVSS v3.1: 5.3 · CWE-548: exposure of information through directory listing.
A static file path returns a browsable index, and documents not linked anywhere in the application can be retrieved directly by name. Unlinked is not unreachable. Disable directory indexes, serve user documents through an authorised handler rather than the filesystem, and treat anything already exposed as disclosed.
What a real engagement adds
A full report also carries an executive summary written for whoever signs the remediation budget, the complete finding set rather than a selection, evidence appendices, a retest of the fixes, and an attestation letter naming the scope and dates — which is usually the artifact your customer or insurer actually asked for.