BASEER Provable security · the friendly adversary

Security assessment · trust package

Security Assessment Report

TARGET OWASP Juice Shop · localhost:3000  ·  RAN 16 Aug 2026  ·  RUN juice-shop-89d8

CriticalOverall posture
20Proven findings
2Critical
8High
10Medium
10/10Classes run
681Agent steps

An autonomous adversary attacked this application across the ten certified attack classes and proved 20 findings. The authentication and authorization layers are fundamentally broken: multiple unauthenticated paths lead directly to full administrative control and remote code execution. Every finding below is a reproduced exploit — not a guess, a maybe, or a scan result. You can re-run every one of them yourself.

The loop

01 · Prove
Done — 20 findings proven, each with its runnable exploit.
02 · Fix
In this report — a clear remediation for every finding. We never touch your code.
03 · Verify
Re-run after you ship. The proof is that the attack now fails — verified, and dated.

Findings — proven, every one

SeverityAttackFindingEndpointCWEStatus
CriticalSQLi SQL Injection auth bypass — admin account takeoverPOST /rest/user/loginCWE-89 Open
CriticalJWT Unsigned JWT (alg:none) accepted — token forgery, full adminGET /api/UsersCWE-347 Open
HighSSTI SSTI (eval) → Remote Code Execution via usernamePOST /profileCWE-94 Open
HighEXPOSURE User records + password hashes exposedGET /rest/memoriesCWE-522 Open
HighSQLi Union-based SQL Injection — full Users table dumpGET /rest/products/searchCWE-89 Open
HighAUTH Broken access control — any user can manage all accountsGET /api/UsersCWE-862 Open
HighAUTH Mass assignment — unauthenticated admin registrationPOST /api/UsersCWE-915 Open
HighAUTH Default admin credentials ([email protected] / admin123)POST /rest/user/loginCWE-798 Open
HighXXE XXE — unauthenticated arbitrary file readPOST /file-uploadCWE-611 Open
HighUPLOAD Stored XSS via ZIP-slip file writePOST /file-uploadCWE-79 Open
MediumEXPOSURE Sensitive file disclosure via /ftp + null-byte bypassGET /ftp/:fileCWE-552 Open
MediumPATH Local File Read via layout paramPOST /dataerasureCWE-22 Open
MediumIDOR IDOR — cross-user basket-item tampering/api/BasketItems/:idCWE-639 Open
MediumIDOR IDOR — read another user's full basketGET /rest/basket/:idCWE-639 Open
MediumIDOR IDOR — address ownership hijackPUT/DELETE /api/Addresss/:idCWE-639 Open
MediumIDOR IDOR — recycle-record disclosure + pickup abuseGET/POST /api/Recycles/:idCWE-639 Open
MediumIDOR IDOR — rewrite another user's product reviewPATCH /rest/products/reviewsCWE-639 Open
MediumSSRF SSRF — profile image URL fetchPOST /profile/image/urlCWE-918 Open
MediumXSS DOM-based XSS — javascript: iframe injectionGET /#/search?q=CWE-79 Open
MediumXSS Stored XSS — username executes on /profilePOST /profileCWE-79 Open
Baseer · provable security Report ID juice-shop-89d8 · Page 1
BASEER Trust package · OWASP Juice Shop

What we ran — the certified ten

Every test is the same ten attack classes, tried the way a real adversary would. This run: all ten hit — each class produced at least one proven finding.

SQLiproven
XSSproven
IDORproven
AUTHproven
RCEproven
SSRFproven
SSTIproven
EXPOSUREproven
PATHproven
UPLOADproven

Scope & methodology

What we tested

The application end to end: login and sign-up, the API behind it, checkout, uploads, and the data those reach — the whole depth an attacker moves through. Target: OWASP Juice Shop (a deliberately vulnerable demo app, used with permission as our labeled showcase).

How

An autonomous adversary, run across the ten certified attack classes — ~35 minutes, 681 agent steps. Nothing is reported unless an exploit ran and reproduced: proof, not prediction. Triage happened by running, never by guessing.

Out of scope — and why

Infrastructure (network, host, cloud configuration) and the long tail of exotic attack classes. Those are a different test. An honest boundary is a feature, not a gap — we say exactly what we covered, and the report never overclaims it.

What this report does not claim

The boundary

  • Known classes, not zero-days. We try the ten certified classes thoroughly. We do not claim we found everything that exists.
  • Not a guarantee. A pass where nothing proved would mean we couldn't break in on this pass, against these ten — a result, not a promise.
  • Re-scanning is the truth keeper. Every release changes the answer. This report is true as of the date above, no longer.

How to read it

  • Every finding is reproducible. Run it yourself — that is the whole difference between this and a scan.
  • Two times, honestly. The real run took ~35 minutes. Reading this report takes minutes.
  • Status is honest. "Open" means proven and not yet re-verified after a fix. We never say "fixed" — we re-attack.

Start here — the highest-impact fixes

1 · Fix the login. Parameterized queries everywhere — the auth bypass and the full database dump both disappear. 2 · Verify tokens with a real signature. An unsigned JWT handing out admin is a broken door, not a bug. 3 · Enforce ownership server-side. Every IDOR on this page is one missing check. 4 · Close the open doors — debug panels, default credentials, the /ftp share. Each remediation, with the reproduction proof for its finding, ships with this report.

After you ship

Apply the fixes, then run the same attacks again. The proof a fix worked is that the attack now fails — verified, and dated. That re-verification is what turns this page from a diagnosis into a defensible posture you can put in front of an investor, a customer, or a regulator.

Baseer · Nairobi · provable security Report ID juice-shop-89d8 · Page 2
BASEER Trust package · findings

Findings — critical

Two findings hand over the entire application to an unauthenticated attacker. Both are the same disease, twice: the server trusts the client. Fix these first.

Critical

01 · SQL Injection — authentication bypass

POST /rest/user/login · CWE-89

What we proved. The login lookup is built from the input string. An unauthenticated attacker bypasses the password check entirely and authenticates as the built-in administrator — the server returns a valid, signed session token carrying role:admin.

Why it matters. Full administrative control without a single credential: user management, every order and basket, the configuration. One input field hands over the whole application.

Remediation. Parameterized queries, everywhere — build the query from data, never from the input. Re-verify: the bypass attack now fails.

Critical

02 · Unsigned JWT accepted — token forgery

GET /api/Users · CWE-347

What we proved. The API accepts a token whose algorithm header claims none and carries no signature. An attacker forges a token asserting the administrator's identity, with no secret.

Why it matters. Identity becomes whatever you claim. The forged token lists all 35 accounts, reads the administrator's saved payment cards, and modifies or deletes any user — a full takeover from a blank page.

Remediation. Verify the signature of every token against the real secret and reject alg:none outright. Re-verify: the forged token is refused.

Baseer · provable security Report ID juice-shop-89d8 · Page 3
BASEER Trust package · findings

Findings — high

Eight findings that read secrets, execute code, or hand over data without breaking anything first. Each is proven — you can reproduce every one.

High

03 · Remote code execution through the template engine

POST /profile · CWE-94

What we proved. A template expression planted in the username field is evaluated server-side. The expression executes on the machine.

Why it matters. Full code execution on the host — secrets, the database, other services, anything the server user can reach.

Remediation. Never evaluate user-supplied input in templates — data and code stay separate. Re-verify: the expression no longer executes.

High

04 · User records and password hashes exposed

GET /rest/memories · CWE-522

What we proved. One unauthenticated request to the photo-wall endpoint returns the complete user table: emails, roles, password hashes, tokens, and last-login IPs.

Why it matters. Every account is exposed, and MD5 hashes fall to trivial cracking (the administrator's is admin123). Credential reuse then spreads the breach beyond this app.

Remediation. Strip sensitive fields from public responses; store passwords with a slow, salted hash. Re-verify: the dump returns nothing sensitive.

High

05 · SQL Injection — full database dump

GET /rest/products/search · CWE-89

What we proved. The search parameter is concatenated into a SQL query. A UNION append reads arbitrary rows from any table.

Why it matters. The complete user table — emails and password hashes — exfiltrated through a search box, unauthenticated.

Remediation. The same parameterization discipline as finding 01. Re-verify: the union returns no extra rows.

High

06 · Broken access control — any user manages all accounts

GET /api/Users · CWE-862

What we proved. The user-management endpoints are not role-gated. A low-privilege token reads, modifies, and deletes any user record.

Why it matters. Every account is manageable by any logged-in user — and next to the JWT flaw, that is full administrative reach.

Remediation. Enforce roles server-side on every user-management route. Re-verify: the low-privilege token is refused.

High

07 · Mass assignment — unauthenticated admin registration

POST /api/Users · CWE-915

What we proved. The registration endpoint trusts a role field supplied by the client. One request creates an account with role:admin.

Why it matters. A persistent administrator identity, created in a single request, no credentials needed — a backdoor that outlives every fix to login.

Remediation. Allow-list the fields a request may set; never accept a role from the client. Re-verify: the role is ignored.

High

08 · Default administrator credentials

POST /rest/user/login · CWE-798

What we proved. The publicly documented default password still authenticates the built-in administrator.

Why it matters. The single most common way in. Anyone who reads the documentation is the administrator.

Remediation. Rotate and disable default credentials; enforce a password policy. Re-verify: the default is refused.

High

09 · XXE — unauthenticated arbitrary file read

POST /file-upload · CWE-611

What we proved. The XML parser resolves external entities. A crafted document reads arbitrary files from the server, unauthenticated.

Why it matters. Server files — system users, configuration, keys — read through the upload handler.

Remediation. Disable external entities in the XML parser. Re-verify: the crafted document reads nothing.

High

10 · Stored XSS via ZIP-slip file write

POST /file-upload · CWE-79

What we proved. Archive entries are written outside the intended directory. An attacker plants attacker-controlled HTML into the served webroot.

Why it matters. Stored XSS on every visitor — the planted file is served to anyone who loads the page. A foothold that spreads.

Remediation. Validate archive entry paths; never write outside the upload directory; serve uploads inert. Re-verify: the planted file no longer executes.

Baseer · provable security Report ID juice-shop-89d8 · Page 4
BASEER Trust package · findings

Findings — medium

Ten findings of cross-user access, disclosure, and input mishandling. None needs a break-in; all are proven.

Medium

11 · Sensitive file disclosure via /ftp

GET /ftp/:file · CWE-552

What we proved. The share lists sensitive files, readable unauthenticated; a null-byte trick downloads them past the extension filter.

Why it matters. The coupon-encryption bytecode is readable and disassembles to reveal the scheme — the coupon system's integrity collapses.

Remediation. Remove public access to the share; serve files through code, not static paths. Re-verify: nothing sensitive is reachable.

Medium

12 · Local file read via layout parameter

POST /dataerasure · CWE-22

What we proved. The layout parameter reaches the filesystem unchecked; a traversal reads the start of any readable file.

Why it matters. Any authenticated user can peek inside server files — a stepping stone to the rest.

Remediation. Validate and restrict the path server-side. Re-verify: traversal returns nothing.

Medium

13 · IDOR — cross-user basket-item tampering

/api/BasketItems/:id · CWE-639

What we proved. Basket items are keyed by id with no ownership check. One account enumerates, modifies, and deletes another user's items.

Why it matters. Any basket is editable by anyone — cart contents, quantities, and order values can be inflated or deflated.

Remediation. Check ownership server-side on every object access. Re-verify: another account's items are refused.

Medium

14 · IDOR — read another user's full basket

GET /rest/basket/:id · CWE-639

What we proved. The basket endpoint trusts the client for ownership. A victim's basket id returns its full contents.

Why it matters. Basket contents, quantities, coupon state, and owner mapping — disclosed.

Remediation. Bind the basket to the session, never the client id. Re-verify: foreign baskets are refused.

Medium

15 · IDOR — address ownership hijack

PUT/DELETE /api/Addresss/:id · CWE-639

What we proved. Saved addresses are keyed by id with no ownership check. Account A modifies and deletes account B's address.

Why it matters. Full name, mobile, and street of any user — disclosed and mutable.

Remediation. An ownership check on every address operation. Re-verify: foreign addresses are refused.

Medium

16 · IDOR — recycle-record disclosure and pickup abuse

GET/POST /api/Recycles/:id · CWE-639

What we proved. Recycle records are keyed by id with no ownership check. Cross-user records are read, and pickups raised against addresses that never asked.

Why it matters. Another user's records disclosed; unsolicited pickups booked at their address.

Remediation. Ownership checks on both read and write. Re-verify: cross-user records are refused.

Medium

17 · IDOR — rewrite another user's product review

PATCH /rest/products/reviews · CWE-639

What we proved. A review id is mutable across users. One account silently rewrites another's review — "MODIFIED BY ALICE — original bob text gone."

Why it matters. Reviews are a trust signal; rewriting them poisons them — a defacement with a business cost.

Remediation. Bind reviews to their author; reject cross-user patches. Re-verify: the rewrite is refused.

Medium

18 · SSRF — profile image URL fetch

POST /profile/image/url · CWE-918

What we proved. The image feature fetches a user-supplied URL server-side. The server reached its own loopback API.

Why it matters. Internal services that were never meant to face the internet become reachable through the app.

Remediation. Block private ranges at the fetch boundary; don't follow user-supplied URLs. Re-verify: the internal fetch fails.

Medium

19 · DOM-based XSS

GET /#/search?q= · CWE-79

What we proved. The search page reflects input into a scriptable sink; a crafted URL executes attacker code.

Why it matters. Attacker JavaScript runs in a visitor's session — and the session token sits in a non-HttpOnly cookie. Session theft.

Remediation. Escape on output; mark the session cookie HttpOnly and Secure. Re-verify: the injected code no longer fires.

Medium

20 · Stored XSS — username

POST /profile · CWE-79

What we proved. The profile page renders the username unescaped. A script stored in the name fires for every visitor to the page.

Why it matters. Persistent attacker code on a page other users load — a watering hole inside the app.

Remediation. Escape all server-rendered user input; set a strict CSP. Re-verify: the stored script no longer executes.

Baseer · provable security Report ID juice-shop-89d8 · Page 5
BASEER Trust package · remediation

The order to fix things — highest impact first

1 · Stop trusting the client for identity. Parameterized queries (findings 01, 05) and real token verification (02) collapse half the report: the auth bypass, the database dump, the forged admin, the mass-assignment backdoor, the broken access control.
2 · Kill the defaults and the open doors. Rotate default credentials (08), close the /ftp share and the debug surface (11), remove sensitive fields from public responses (04).
3 · Enforce ownership server-side. One missing check is the whole IDOR family (13–17): baskets, addresses, records, reviews.
4 · Harden the input channels. Templates and XML must never evaluate user input (03, 09); uploads are validated by content, not extension, and served inert (10); escape on every output path (19, 20); block internal fetches (18); validate paths (12).

After you ship — verification

Apply the fixes, then we run the same attacks again. The proof a fix worked is that the attack now fails — verified, and dated. That re-verification is what turns this page from a diagnosis into a posture you can defend. A grade is issued when the loop closes, never before.

What we don't claim

The boundary

  • Known classes, not zero-days. We tried the ten certified classes thoroughly. We do not claim we found everything that exists.
  • Not a guarantee. A pass where nothing proved would mean we couldn't break in on this pass, against these ten — a result, not a promise.
  • Re-scanning is the truth keeper. Every release changes the answer. This report is true as of the date on page one, no longer.

How to read it

  • Every finding is reproducible. Run it yourself — that is the whole difference between this and a scan.
  • Two times, honestly. The real run took ~35 minutes. Reading this report takes minutes.
  • Status is honest. We never say "fixed." We re-attack, and the attack now fails — verified, and dated.
Baseer · Nairobi · provable security Report ID juice-shop-89d8 · Page 6