Active engagement · verified findings

Deep Audit sample: every finding, proven.

This is a complete Deep Security Audit report run against OWASP Juice Shop — a deliberately vulnerable e-commerce app built for security training, so we can publish real findings with nothing redacted. Where the $49 check tells you what's visible from the street, this is what we send after actively testing the doors: each finding manually reproduced, scored, and backed by the actual request and response.

Targetowasp-juice.shop
EngagementActive audit (auth + API)
WindowMay 27–29, 2026
Methodologyindustry-standard, manually verified
Report IDDA-2026-0529-01
How to read this: every High/Critical finding below was reproduced by hand before it made the report. Automated scanner output that couldn't be confirmed lives in an internal noise log and is deliberately excluded — you only pay for, and read, what's real.
Owner summary

If you owned this site, here's the email I'd send you.

The bottom line

Someone can log in as your administrator without knowing any password, and can read other customers' shopping baskets by changing a number in the address bar. Both are confirmed working — we did them, captured the proof, and stopped there. These are the two things to fix this week.

What a bad actor could do today

Take over the admin account and your back office, pull other customers' order and basket data, browse downloadable files left in a public directory, and run scripts in a visitor's browser through the search box. Any one of these is a reportable data-breach risk.

Fix order for your developer or IT

1) Parameterize the login query to kill the SQL injection. 2) Add an ownership check on the basket endpoint. 3) Lock down or remove the /ftp directory. 4) Encode search output and add a Content-Security-Policy. 5) Replace wildcard CORS with your own domain.

Technical appendix — verified findings

Each finding includes severity, CVSS v3.1 score, CWE reference, the evidence we captured, reproduction steps, and a specific fix. This is the section you forward to whoever maintains the site.

Critical CVSS 9.8 CWE-89 · SQL Injection Manually verified

Authentication bypass via SQL injection in login

The login form builds its database query by pasting the email straight into the SQL string. Supplying ' OR 1=1-- as the email turns the query into one that always matches the first user — the administrator — and logs in with no valid password.

Evidence — request / response
# Request (email field carries the injection)
POST /rest/user/login HTTP/1.1
Host: owasp-juice.shop
Content-Type: application/json

{"email":"' OR 1=1--","password":"x"}

# Response — authenticated token issued for the admin account
HTTP/1.1 200 OK
{"authentication":{
  "token":"eyJhbGci...",
  "umail":"[email protected]"
}}
Reproduction
  1. Open the login page.
  2. Enter ' OR 1=1-- in the email field and any value in the password field.
  3. Submit. The server returns a valid session token for [email protected] — full administrative access, no password required.
Fix: Never concatenate user input into SQL. Use parameterized queries / prepared statements (bound parameters) for the login lookup. With the ORM, pass the email as a bound value rather than building the WHERE clause as a string. Add server-side input validation on the email field as defense in depth.
Critical CVSS 8.1 CWE-639 · IDOR / Broken Access Control Manually verified

Broken access control — read any user's basket by ID

The basket endpoint returns whatever basket ID you ask for without checking that it belongs to the logged-in user. Authenticated as a normal test account (basket id=2), requesting id=1 returns another user's basket contents.

Evidence — request / response
# Logged in as our test user (owns basket 2). We request basket 1.
GET /rest/basket/1 HTTP/1.1
Host: owasp-juice.shop
Authorization: Bearer eyJhbGci...<test-user-token>

# Response — another user's basket returned. No ownership check.
HTTP/1.1 200 OK
{"status":"success","data":{
  "id":1,"UserId":1,
  "Products":[{"name":"Apple Juice (1000ml)","quantity":3}]
}}
Reproduction
  1. Log in with any account and note your own basket ID.
  2. Send a GET to /rest/basket/<a different ID> with your own token.
  3. The server returns the other user's basket instead of rejecting the request. We confirmed this read-only and did not alter any data.
Fix: On every basket request, verify the requested basket's UserId matches the authenticated user's ID before returning data. Reject with 403 otherwise. Apply the same ownership check to every object-ID endpoint (orders, addresses, feedback).
High CVSS 7.5 CWE-548 · Exposed Directory Manually verified

Unauthenticated file directory at /ftp

Requesting /ftp returns a full directory listing with no login. Sensitive files are downloadable, including a KeePass password database (.kdbx) and backup/config files. The /robots.txt entry pointed straight at it.

Evidence — request / response
GET /ftp HTTP/1.1
Host: owasp-juice.shop

HTTP/1.1 200 OK
<ul>
  <li><a href="/ftp/coupons_2013.md.bak">coupons_2013.md.bak</a></li>
  <li><a href="/ftp/eastere.gg">eastere.gg</a></li>
  <li><a href="/ftp/encrypt.pyc">encrypt.pyc</a></li>
</ul>
Reproduction
  1. Browse to https://owasp-juice.shop/ftp with no authentication.
  2. The directory listing renders. Files are individually downloadable.
  3. Confirmed the listing and a single file fetch only — we did not download or retain sensitive contents.
Fix: Remove the /ftp directory from the web root or place it behind authentication. Disable directory listing at the server level. Move any secrets (password databases, backups) out of web-served paths entirely. Remove the /ftp hint from robots.txt.
Medium CVSS 6.1 CWE-79 · Reflected XSS Manually verified

Reflected XSS in the search parameter

The q search parameter is reflected into the page without encoding, so an <iframe>/script payload in the URL executes in the visitor's browser. A crafted link sent to a customer could run script in their session.

Evidence — request / response
GET /#/search?q=<iframe src="javascript:alert(`xss`)"> HTTP/1.1
Host: owasp-juice.shop

# The payload is reflected into the DOM unescaped and executes.
Result: alert dialog fires in the browser; payload rendered verbatim.
Reproduction
  1. Load the search route with the iframe/script payload in the q parameter.
  2. The script executes in the page context — confirmed with a harmless alert, no data touched.
Fix: HTML-encode all user input before rendering it. Use the framework's built-in output binding instead of injecting raw HTML. Add a Content-Security-Policy as a second line of defense (see next finding).
Medium CVSS 5.3 CWE-942 / CWE-693 · CORS + Missing CSP Manually verified

Wildcard CORS and no Content-Security-Policy

API responses carry Access-Control-Allow-Origin: *, so any website can read them from a victim's browser. There is also no Content-Security-Policy, so if a script does slip in (see the XSS above) the browser has nothing telling it to refuse.

Evidence — response headers
GET /rest/products/search?q=apple HTTP/1.1
Host: owasp-juice.shop

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *        # any origin can read this
Content-Security-Policy: <not set>   # no XSS backstop
X-Content-Type-Options: <not set>
Reproduction
  1. Request any API endpoint and inspect the response headers.
  2. Confirm Access-Control-Allow-Origin: * is present and no CSP header is returned.
Fix: Replace the wildcard with your own domain(s): Access-Control-Allow-Origin: https://yourdomain.com. Add a Content-Security-Policy (start with default-src 'self' and loosen as needed) and X-Content-Type-Options: nosniff.
What didn't make the report: the automated scanners also flagged several "potential" issues — a suspected outdated library and two header warnings — that we could not reproduce by hand or that turned out to be false positives. Those are logged internally and excluded here. The five findings above are the ones we confirmed are real.

Scope & method for this engagement

Every deep audit is bounded by a signed scope-of-work agreement before any active testing starts.

Engagement parameters
Authorized targetowasp-juice.shop only — single domain, in writing
Signed
Authenticated testingClient-provided test account; no brute-force, no credential stuffing
In scope
Injection testingDetection + read-only proof; no data modified or exfiltrated
In scope
Disruptive testingNo DoS, load, or stress testing performed
Excluded
CleanupTemporary testing setup wiped within 7 days; evidence kept 90 days for re-test
Per agreement
Free re-testFocused re-check of these findings within 30 days of delivery
Included

Want this depth on your own site?

The deep audit is a one-time engagement, $349 for a standard single-site audit (larger scope quoted up front), and starts only after you sign a scope-of-work agreement. Every finding you get is manually verified and proven, like the ones above, with your URLs and your fixes.

Book a deep audit