POST /dataerasure performs state change with cookie auth and no CSRF protection
The data-erasure POST endpoint creates a privacy/deletion request using cookie-based authentication with no CSRF token, custom-header gate, strict SameSite, or origin check — a malicious site can trigger account deletion against the victim's session.
routes/dataErasure.ts:74-127 registers router.post('/', …) that
- Identifies the caller via the session cookie:
const loggedInUser = security.authenticatedUsers.get(req.cookies.token)
- Mutates server state — creates a
PrivacyRequestmarked for account deletion:
await PrivacyRequestModel.create({
UserId: loggedInUser.data.id,
deletionRequested: true
})
res.clearCookie('token')
- Optionally triggers the local-file-read code path (see separate finding) when
req.body.layoutis supplied.
There is no CSRF middleware anywhere in the codebase — a repo-wide grep for csrf|csurf returns zero matches in server.ts, app.ts, and the router itself. The session cookie is set in lib/insecurity.ts:193 as res.cookie('token', token) with no sameSite/httpOnly/secure flags, so the application relies entirely on the browser's Lax default — which still permits top-level form POSTs from cross-origin pages in several edge cases (e.g. fresh top-level navigations during a short grace window in Chrome, and outright on browsers that haven't adopted Lax-by-default). The handler also accepts URL-encoded form bodies (server.ts:305 registers bodyParser.urlencoded({extended: true})), so no preflight is required and no custom header is mandated. No Origin/Referer check is performed.
An attacker who can lure an authenticated victim to a malicious page can submit a hidden form that requests deletion of the victim's account, and can simultaneously exploit the LFR path by setting layout=....
Host an attacker page that auto-submits this form when the victim visits while logged in to the Juice Shop:
<form action="https://target/dataerasure" method="POST">
<input name="email" value="victim@example.com">
<input name="securityAnswer" value="anything">
</form>
<script>document.forms[0].submit();</script>
The browser auto-attaches Cookie: token=..., the handler authenticates the request as the victim, and PrivacyRequestModel.create({ UserId: …, deletionRequested: true }) runs. The session cookie is also cleared (res.clearCookie('token')), forcibly logging the victim out.
Cross-site forgery of an account-deletion/privacy request against any authenticated user, plus forced logout. When combined with the LFR finding, the same CSRF vector can be used to exfiltrate the first ~100 bytes of any server file by inducing the victim's browser to issue the request (the response body is returned to the victim, not the attacker, but the side-effect on PrivacyRequestModel and forced logout are immediate).
The POST handler at router.post('/', ...) authenticates solely via security.authenticatedUsers.get(req.cookies.token) and then performs a state-changing operation (PrivacyRequestModel.create({ UserId: loggedInUser.data.id, deletionRequested: true }) plus res.clearCookie('token')) with no CSRF token check, no Origin/Referer validation, and no custom-header gate. The route accepts standard form bodies, so a cross-origin auto-submitting form would trigger account deletion and forced logout against any logged-in victim. Scope explicitly says to evaluate as a real production app and not downgrade because Juice Shop is intentionally vulnerable.
The attacker themselves needs no credentials (PR=N) — they only need to lure an authenticated victim to a malicious page (UI=R), at which point the auto-submitted cross-origin form at routes/dataErasure.ts:74 is authenticated by the victim's req.cookies.token because no CSRF token, custom-header gate, or Origin/Referer check exists and the cookie is set without SameSite/Secure flags. Integrity is High because PrivacyRequestModel.create({ UserId, deletionRequested: true }) forges an account-deletion privacy request against the victim, and Availability is High because res.clearCookie('token') forcibly logs the victim out and the deletion request can lead to loss of access to the account. Confidentiality is None for this finding in isolation (the LFR exfiltration is scored separately and its response returns to the victim, not the attacker). Scope is Unchanged — the impact is on the same Juice Shop application's user/privacy data, not a different security authority.
- CWE-352
- OWASP A01:2021 Broken Access Control