Scan results. 96 findings across 504 files.
C:\Users\User\Desktop\demo\juice-shop
All findings, filterable
- CRITICALconfirmedvulnerable-dependency·frontend/package.json:58-58
Likely typosquat: `ngy-cookie` (looks like `ngx-cookie`)
`ngy-cookie` is one character off from the well-known `ngx-cookie` / `ngx-cookie-service` Angular libraries and is not itself a widely-recognized package, fitting the typosquat profile.
75% - CRITICALconfirmedxss·frontend/src/app/administration/administration.component.html:25-27
Stored XSS via [innerHTML] of user.email in administration user table
The admin user table renders `user.email` through Angular `[innerHTML]`, and the component pre-wraps every email in `DomSanitizer.bypassSecurityTrustHtml` after string-interpolating it into an HTML span — emails containing HTML are executed in the admin's browser.
90% - CRITICALconfirmedxss·frontend/src/app/administration/administration.component.html:59-61
Stored XSS via [innerHTML] of feedback comment in administration feedback table
The feedback table renders `feedback.comment` through Angular `[innerHTML]` after the component wraps each comment in `DomSanitizer.bypassSecurityTrustHtml`, allowing attacker-supplied feedback content to execute script in the admin's browser.
90% - CRITICALconfirmedxss·frontend/src/app/administration/administration.component.ts:70-95
XSS via bypassSecurityTrustHtml on user-controlled email and feedback comment in AdministrationComponent
User emails and feedback comments are wrapped in raw HTML and marked trusted via DomSanitizer.bypassSecurityTrustHtml in the admin panel, allowing stored XSS that fires in an administrator's browser.
90% - CRITICALconfirmedxss·frontend/src/app/feedback-details/feedback-details.component.html:17-19
Stored XSS via [innerHTML] of feedback comment in feedback-details dialog
The feedback-details dialog renders `feedback` via Angular `[innerHTML]`; the value is the `feedback.comment` field passed from the administration component already wrapped in `bypassSecurityTrustHtml`, executing attacker-controlled HTML in the admin's browser when a row is clicked.
85% - CRITICALconfirmedweak-password-reset·frontend/src/app/forgot-password/forgot-password.component.ts:83-90
Password reset gated only by security question (knowledge factor)
The forgot-password flow resets a user's password using only (email, security-question answer, new password) with no emailed token or proof-of-control of the verified channel.
95% - CRITICALconfirmedalgorithm-confusion·lib/insecurity.ts:188-196
jwt.verify on session cookie does not pin algorithm — RS256→HS256 confusion possible
updateAuthenticatedUsers calls jwt.verify(token, publicKey, cb) without an `algorithms` option, allowing an attacker to forge tokens by signing HS256 with the published RSA public key.
95% - CRITICALconfirmedjwt-handling·lib/insecurity.ts:24-24
RSA signing private key hardcoded in source
The RSA private key used by `authorize()` to mint session JWTs is a hardcoded string literal in `lib/insecurity.ts`, so anyone with read access to the repo (or a deployed source map / package) can sign arbitrary tokens.
95% - CRITICALconfirmedhardcoded-secrets·lib/insecurity.ts:22-22
Hardcoded RSA private key used for JWT signing
A complete RSA private key is embedded as a string literal and used to sign JWTs and derive the deluxe-token HMAC.
99% - CRITICALconfirmedhardcoded-secrets·lib/insecurity.ts:41-41
Hardcoded HMAC secret used for password/data signing
The HMAC-SHA256 key `pa4qacea4VK9t9nGv7yZtwmj` is hardcoded and used as the application's general-purpose HMAC secret.
98% - CRITICALconfirmedweak-password-policy·models/user.ts:76-81
User model hashes password with no length or strength check
The Sequelize User model's password setter calls security.hash() directly on whatever string the user supplies, with no minimum length, complexity, common-password, or username-equality check — and there is no upstream validator on the registration or reset-password paths to compensate.
90% - CRITICALconfirmedvulnerable-dependency·package.json:103-103
express-jwt pinned to 0.1.3 — pre-6.0 algorithm verification bypass
express-jwt is pinned at 0.1.3, far below the 6.0.0 line that fixed CVE-2020-15084 (missing algorithm verification allowing JWT signature bypass).
95% - CRITICALconfirmedvulnerable-dependency·package.json:115-115
jsonwebtoken pinned to 0.4.0 — pre-fix algorithm confusion
jsonwebtoken is pinned at 0.4.0, predating CVE-2015-9235 (alg=none / HS-vs-RS algorithm confusion) and every subsequent security fix through 9.x.
95% - CRITICALconfirmedrate-limit-bypass·routes/2fa.ts:16-48
2FA verify endpoint rate limit bypassable via spoofed X-Forwarded-For
The /rest/2fa/verify rate limit keys on req.ip, but trust proxy is enabled globally so attackers can rotate the X-Forwarded-For header to obtain unlimited TOTP-guess buckets and brute-force the 6-digit second factor.
85% - CRITICALconfirmedsandbox-runtime-script·routes/b2bOrder.ts:21-24
Untrusted script executed in Node vm without memory limit or restricted host surface
User-controlled orderLinesData is evaluated through notevil inside a Node vm context that has only a wall-clock timeout — no memory budget and no isolation of host globals, so the runtime is unsuitable as a sandbox for untrusted code.
90% - CRITICALconfirmedhardcoded-secrets·routes/checkKeys.ts:10-12
Hardcoded BIP39 mnemonic seed phrase used to derive Ethereum private key
A real 12-word BIP39 mnemonic is embedded as a string literal and used to derive an Ethereum wallet's private key inside a request handler.
85% - CRITICALconfirmedxxe·routes/fileUpload.ts:81-93
XXE via libxmljs2 parseXml with noent:true on uploaded XML
handleXmlUpload parses untrusted uploaded XML with libxmljs2 using noent:true, which expands external entities and enables file disclosure / SSRF / DoS via XXE.
99% - CRITICALconfirmedzip-slip·routes/fileUpload.ts:40-49
Zip Slip in handleZipFileUpload via broken containment check
The ZIP extractor writes entries to `uploads/complaints/<entry.path>` after a broken `absolutePath.includes(path.resolve('.'))` containment check, allowing an attacker-controlled archive entry name like `../../ftp/legal.md` to overwrite arbitrary files inside the project tree.
98% - CRITICALconfirmedfile-upload-validation·routes/fileUpload.ts:68-74
checkFileType middleware does not actually enforce an extension allowlist
checkFileType inspects the filename extension only to update a CTF challenge state and unconditionally calls next(); any extension is accepted by the upload pipeline.
90% - CRITICALconfirmedfile-upload-validation·routes/fileUpload.ts:27-56
ZIP entries extracted to disk using attacker-controlled paths (weak zip-slip guard)
handleZipFileUpload writes each archive entry to `uploads/complaints/<entry.path>` after a containment check that compares `absolutePath.includes(path.resolve('.'))`, which is bypassable and still allows writing anywhere under the project root.
85% - CRITICALconfirmedfile-upload-validation·routes/fileUpload.ts:76-103
XML upload parsed with external entities enabled (XXE)
handleXmlUpload feeds uploaded XML directly into libxmljs2 with `noent: true`, enabling external entity expansion on attacker-supplied documents with no size or content validation.
90% - CRITICALconfirmeddeprecated-endpoint·routes/fileUpload.ts:78-107
Deprecated XML upload handler still parses XML with external entities and leaks output via error
`handleXmlUpload` advertises itself as deprecated and returns HTTP 410, yet still parses uploaded XML with `noent: true` (XXE) and then forwards the parsed content into `next(new Error(...))`, leaking parser output to the response.
95% - CRITICALconfirmedsql-injection·routes/login.ts:33-33
SQL injection in /rest/user/login via template-literal email/password
The login query is built by interpolating req.body.email straight into a raw SQL string passed to sequelize.query, enabling authentication bypass and arbitrary SELECT.
98% - CRITICALconfirmedjs-sql-raw·routes/login.ts:33-33
Raw sequelize.query with template-literal interpolation in login handler
sequelize.query is called with a backtick string interpolating req.body.email instead of using the replacements/bind option, the Sequelize raw-SQL escape hatch.
98% - CRITICALconfirmedrate-limit-bypass·routes/login.ts:32-33
/rest/user/login is not rate-limited
The login endpoint has no rate-limit / lockout middleware, enabling unlimited credential stuffing and password brute-force against any account.
90% - CRITICALconfirmedfile-upload-validation·routes/profileImageUrlUpload.ts:19-36
Profile image upload fetches arbitrary URL with no size limit and no content-type validation, SVG allowed under web root
profileImageUrlUpload streams a user-supplied URL to disk under the web-served assets directory with no size cap, no MIME/magic-number check, and an extension allowlist that includes SVG, enabling stored XSS and disk-fill DoS.
90% - CRITICALconfirmedweak-password-reset·routes/resetPassword.ts:16-52
Password reset gated solely on security-question answer
The /resetPassword endpoint allows any anonymous caller to set a new password for any account given only the target email and a matching security answer, with no emailed token, no rate limit, and no proof of email control.
98% - CRITICALconfirmedsql-injection·routes/search.ts:21-23
SQL injection via template-literal interpolation of req.query.q into raw Sequelize query
`searchProducts` builds a raw `SELECT * FROM Products ...` string by template-interpolating the unsanitized `req.query.q` value (only truncated to 200 chars) and hands it to `sequelize.query`, allowing classic UNION-based SQL injection.
98% - CRITICALconfirmedalgorithm-confusion·routes/verify.ts:119-125
jwt.verify called without algorithms option enables RS256→HS256 algorithm confusion
jwtChallenge() calls jwt.verify with the RSA public key and no algorithms option, so a token whose header advertises HS256 will be verified using the public key as an HMAC secret — accepting attacker-forged tokens.
85% - CRITICALconfirmedrate-limit-bypass·server.ts:340-344
Reset-password rate limit keyed on attacker-controlled X-Forwarded-For header
The only rate limit protecting `POST /rest/user/reset-password` derives its key from the `X-Forwarded-For` request header, which the client controls — an attacker can rotate the header per request and trivially exceed the 100-request window.
90% - CRITICALconfirmedtwo-factor-bypass·server.ts:451-454
Brute-force-friendly rate limit on 2FA TOTP verification endpoint
`POST /rest/2fa/verify` is rate-limited at 100 attempts per 5 minutes per IP with no per-account lockout, and the verifier uses `epochTolerance: 30` (≈30 minutes of valid codes); combined this is well within practical brute-force range of a 6-digit TOTP.
70% - CRITICALconfirmedweak-password-reset·server.ts:315-319
Reset-password rate limit trivially bypassed via spoofed X-Forwarded-For
The express-rate-limit middleware on /rest/user/reset-password keys requests off the client-controlled X-Forwarded-For header, so an attacker can rotate that header per request and brute-force security answers without ever hitting the 100/5-minute cap.
80% - HIGHconfirmedxss·frontend/src/app/data-export/data-export.component.ts:71-71
Data export writes user-controlled JSON to a new window via document.write
`document.write(this.userData)` renders a JSON payload that embeds user-controlled fields (memory captions, review messages) as raw HTML, allowing stored XSS in the export popup.
85% - HIGHconfirmedxss·frontend/src/app/last-login-ip/last-login-ip.component.html:10-10
XSS via lastLoginIp HTTP header rendered with bypassSecurityTrustHtml in [innerHTML]
`lastLoginIp`, derived from the attacker-controllable `true-client-ip` header and then wrapped with `bypassSecurityTrustHtml`, is bound to `[innerHTML]`, allowing stored XSS in the Last Login IP screen.
90% - HIGHconfirmedxss·frontend/src/app/product-details/product-details.component.html:16-16
XSS via [innerHTML] binding of product description in product-details dialog
Product description is rendered through `[innerHTML]` and the caller (`search-result.component.ts`) supplies a `SafeHtml` value produced by `bypassSecurityTrustHtml`, disabling Angular's default sanitization and enabling stored XSS through product description content.
85% - HIGHconfirmedrce·routes/b2bOrder.ts:17-35
RCE via vm.runInContext evaluating user-controlled orderLinesData
b2bOrder evaluates request-supplied orderLinesData inside Node's vm context via notevil's safeEval; both the vm module and notevil have documented sandbox-escape paths leading to remote code execution.
95% - HIGHconfirmedrate-limit-bypass·routes/changePassword.ts:13-62
Missing rate limit on /rest/user/change-password enables credential brute-force and pivot
The password-change endpoint has no rate limiting, allowing unlimited attempts at brute-forcing the current password or hammering the endpoint with stolen tokens.
85% - HIGHconfirmedcsrf·routes/dataErasure.ts:74-127
POST /dataerasure performs state change with cookie auth and no CSRF protection
The data-erasure POST endpoint creates a privacy/deletion request using cookie-based authentication with no CSRF token, custom-header gate, strict SameSite, or origin check — a malicious site can trigger account deletion against the victim's session.
80% - HIGHconfirmedfile-upload-validation·routes/fileUpload.ts:61-66
checkUploadSize middleware never rejects oversized uploads
checkUploadSize only triggers a challenge marker when a file exceeds 100 KB but always calls next(), so there is no actual server-side size enforcement on file uploads.
90% - HIGHconfirmedfile-upload-validation·routes/fileUpload.ts:105-130
YAML upload deserialised without size or content validation
handleYamlUpload invokes yaml.load on the raw uploaded buffer with no size cap, no MIME/extension allowlist, and no schema, exposing the server to YAML-bomb DoS amplification.
80% - HIGHconfirmeddeprecated-endpoint·routes/fileUpload.ts:110-137
Deprecated YAML upload handler still parses YAML and leaks parsed content via error
`handleYamlUpload` is labeled deprecated and sets HTTP 410, but still calls `yaml.load` on attacker-supplied input and passes the JSON-stringified result into `next(new Error(...))`, exposing it in the response and enabling YAML-bomb DoS.
90% - HIGHconfirmedmissing-access-control·routes/order.ts:32-158
IDOR in POST /rest/basket/:id/checkout — checkout any basket and bill/credit an arbitrary user's wallet
The /rest/basket/:id/checkout handler trusts both the URL basket id and a client-supplied `req.body.UserId` to charge/credit wallets, so any authenticated user can place orders against another user's basket and debit or credit any wallet they choose.
97% - HIGHconfirmeduntrusted-redirect-following·routes/profileImageUrlUpload.ts:24-27
SSRF via fetch() that follows redirects with caller-controlled URL
`profileImageUrlUpload` calls `fetch(req.body.imageUrl)` with no allowlist and the WHATWG fetch default `redirect: "follow"`, so an attacker can point the server at any host (and chain through redirects to internal targets such as cloud metadata services).
90% - HIGHconfirmedjs-sql-raw·routes/search.ts:22-22
Raw sequelize.query() with template-literal interpolation of user input
The Sequelize escape-hatch `sequelize.query()` is invoked with a template literal that interpolates `req.query.q` directly into the SQL string instead of using the `replacements`/`bind` option.
98% - HIGHconfirmedmissing-access-control·routes/updateProductReviews.ts:13-29
IDOR in PATCH /rest/products/reviews — any authenticated user can edit any product review
The authenticated review-update handler updates a Mongo review document looked up by client-supplied `_id` without verifying the caller is the review author, letting any logged-in user overwrite anyone else's product review.
97% - HIGHconfirmedrce·routes/userProfile.ts:52-66
eval() of substring from user-controlled username enables RCE/SSTI
getUserProfile evaluates a substring of the persisted username as JavaScript via eval(), and the username originates from user input through the profile update endpoint — yielding full remote code execution on the server.
95% - HIGHconfirmedssti·routes/userProfile.ts:74-90
SSTI via username interpolated into Pug template source before compile
User-controlled `username` is string-concatenated into a Pug template source, then `pug.compile(template)` is invoked, allowing server-side template injection (and explicit `eval()` of `#{...}` content).
95% - HIGHconfirmedfile-upload-validation·server.ts:431-451
multer uploadToDisk has no fileSize limit and writes to a publicly served directory
The `uploadToDisk` multer instance used by `POST /rest/memories` enforces no `limits.fileSize` and persists files into the web-served static assets directory, allowing disk-exhaustion DoS by uploading arbitrarily large files.
70% - MEDIUMconfirmedvulnerable-dependency·frontend/package.json:53-53
Abandoned dependency: `font-mfizz@^2.4.1`
`font-mfizz` has had no releases for roughly a decade and the upstream project is dormant; flag for replacement with a maintained icon font.
55% - MEDIUMuncertainvulnerable-dependency·frontend/package.json:60-60
Outdated major: `socket.io-client@^3.1.0`
`socket.io-client@^3.x` is two majors behind current (v4) and has had advisories in the v3 line; pin should be upgraded and re-audited.
45% - MEDIUMconfirmedxss·frontend/src/app/about/about.component.html:50-53
Stored XSS via [innerHTML] of bypassSecurityTrustHtml-wrapped feedback comment in About page
The customer-feedback gallery renders `item?.args` directly via Angular `[innerHTML]`, and the component populates `args` from raw user-submitted feedback comments wrapped in `DomSanitizer.bypassSecurityTrustHtml`, allowing stored XSS in any visitor to the About page.
90% - MEDIUMconfirmedxss·frontend/src/app/about/about.component.ts:111-124
XSS via bypassSecurityTrustHtml on user-controlled feedback comments in AboutComponent
Feedback comments fetched from the backend are interpolated into an HTML string and then marked trusted via DomSanitizer.bypassSecurityTrustHtml, allowing stored XSS in the About page gallery.
90% - MEDIUMconfirmedxss·frontend/src/app/last-login-ip/last-login-ip.component.ts:37-41
Stored XSS via bypassSecurityTrustHtml on attacker-controlled True-Client-IP header
`lastLoginIp` (sourced from the user's `True-Client-IP` request header on the server) is wrapped in `DomSanitizer.bypassSecurityTrustHtml` and rendered via `[innerHTML]`, allowing arbitrary HTML/JS execution in the victim's session.
90% - MEDIUMconfirmedxss·frontend/src/app/search-result/search-result.component.html:11-11
DOM XSS via search query parameter rendered with [innerHTML] after bypassSecurityTrustHtml
The URL query parameter `q` is wrapped with `DomSanitizer.bypassSecurityTrustHtml` and bound to `[innerHTML]`, allowing arbitrary HTML/script execution from a crafted link.
95% - MEDIUMconfirmedxss·frontend/src/app/search-result/search-result.component.ts:130-142
Reflected DOM XSS via `q` query parameter in search results
The `q` query parameter is passed through `DomSanitizer.bypassSecurityTrustHtml` and then rendered via `[innerHTML]` in the template, producing a reflected DOM-based XSS.
95% - MEDIUMconfirmedxss·frontend/src/app/search-result/search-result.component.ts:107-111
Stored XSS via product descriptions rendered with bypassSecurityTrustHtml
Product descriptions fetched from the backend are wrapped with `bypassSecurityTrustHtml` and rendered with `[innerHTML]`; because PUT `/api/Products/:id` is left unauthenticated server-side, any user can persist an XSS payload in a product description.
90% - MEDIUMconfirmedweak-password-reset·frontend/src/app/Services/security-question.service.ts:24-29
Security question lookup by email exposed to anonymous callers
The frontend service fetches a user's security question text by email with no authentication, enabling attackers to shop accounts for guessable answers used in the password reset flow.
70% - MEDIUMconfirmedxss·frontend/src/app/track-result/track-result.component.ts:48-48
Reflected XSS via bypassSecurityTrustHtml on order tracking result
Order-tracking result interpolates the untrusted `orderId` value into an HTML string and pushes it through `bypassSecurityTrustHtml`, which the template then renders via `[innerHtml]`, enabling arbitrary script execution.
90% - MEDIUMconfirmedsession-cookie-config·lib/insecurity.ts:193-193
Session token cookie set without httpOnly / secure / sameSite
`res.cookie('token', token)` in updateAuthenticatedUsers writes the auth JWT to a cookie with no security attributes, leaving it readable by injected JavaScript, sent over HTTP, and attached to cross-site requests.
90% - MEDIUMconfirmedurl-regex-validation·lib/insecurity.ts:128-134
Open redirect via substring includes check in isRedirectAllowed
isRedirectAllowed uses url.includes(allowedUrl) to validate redirect targets, allowing attackers to bypass the allowlist by embedding an allowlisted URL as a query parameter or path segment.
98% - MEDIUMconfirmedweak-password-policy·models/user.ts:74-79
User password setter hashes any input with no length or strength check
The centralized Sequelize `password` setter hashes the raw plaintext with no length/complexity/common-password validation, and every upstream route (register, change-password, reset-password) relies on it without adding checks.
90% - MEDIUMconfirmedweak-password-policy·models/user.ts:74-79
Weak password policy: User model password setter hashes without length or strength validation
The Sequelize User model hashes every password supplied by the client (registration, password change, password reset) with no minimum length, common-password deny list, or username/email equality check, allowing users to set trivially weak passwords like `'a'` or `'123'`.
90% - MEDIUMconfirmedvulnerable-dependency·package.json:118-118
marsdb listed as a production dependency
marsdb is an abandoned client-side/embedded MongoDB-style library with known unresolved issues; the review brief explicitly names it as flag-worthy.
90% - MEDIUMconfirmedvulnerable-dependency·package.json:133-133
sanitize-html pinned to 1.4.2 — multiple XSS bypass CVEs
sanitize-html is pinned to 1.4.2, a version vulnerable to several documented XSS sanitizer-bypass advisories fixed in 1.20.x / 2.x.
90% - MEDIUMconfirmedvulnerable-dependency·package.json:120-120
median pinned to 0.0.x — pre-release used in production
`median` is pulled in as `^0.0.2`, a 0.0.x release range explicitly flagged by the brief as risky in production.
60% - MEDIUMconfirmedvulnerable-dependency·package.json:148-148
z85 pinned to 0.0.x — pre-release used in production
`z85` is pulled in as `^0.0.2`, a 0.0.x range the brief specifically calls out as production-risky.
55% - MEDIUMconfirmedmissing-access-control·routes/basket.ts:15-36
IDOR in GET /rest/basket/:id allows viewing any user's basket
The authenticated /rest/basket/:id handler fetches a basket purely by the URL id with no scoping to the authenticated user, letting any logged-in user read any other user's basket contents.
98% - MEDIUMconfirmedunverified-lookup·routes/basket.ts:19-32
Cross-user basket access via /rest/basket/:id (IDOR)
retrieveBasket fetches a basket by request-supplied id without verifying the caller owns that basket, allowing any authenticated user to read another user's basket and its products.
95% - MEDIUMconfirmederror-message-leak·routes/checkKeys.ts:28-30
Error message leaked via utils.getErrorMessage in checkKeys catch block
The catch block forwards the raw error message to the client via utils.getErrorMessage(error), which returns error.message / String(error) and can leak internal details.
60% - MEDIUMconfirmedmissing-access-control·routes/coupon.ts:10-34
IDOR in PUT /rest/basket/:id/coupon/:coupon allows applying coupons to any basket
The authenticated apply-coupon endpoint updates the basket identified solely by URL id without verifying the basket belongs to the caller, letting a user attach (or clear) coupons on other users' baskets.
95% - MEDIUMconfirmederror-message-leak·routes/createProductReviews.ts:30-32
Raw error message returned in 500 response from review creation
The catch block sends utils.getErrorMessage(err) — which extracts the underlying error's message — directly to the HTTP client, leaking internal/database error details.
75% - MEDIUMconfirmedpath-traversal·routes/dataErasure.ts:103-121
Local File Read via req.body.layout in dataErasure POST (blocklist bypass)
`req.body.layout` is fed into `path.resolve()` and then into `res.render` template locals, with only a substring blocklist for guard — letting an attacker read arbitrary server files via the Pug layout include.
95% - MEDIUMconfirmederror-message-leak·routes/deluxe.ts:57-59
Outer catch leaks error message via utils.getErrorMessage in upgradeToDeluxe response
The outer catch block in upgradeToDeluxe concatenates utils.getErrorMessage(err) into the JSON response, leaking raw underlying error text (likely err.message) to the client.
80% - MEDIUMconfirmederror-message-leak·routes/fileUpload.ts:91-103
XML parser error message leaked to client in handleXmlUpload catch block
The catch block in handleXmlUpload propagates the raw libxml/VM parser error message back to the client via next(new Error(...)), leaking internal parser/library details.
60% - MEDIUMconfirmederror-message-leak·routes/fileUpload.ts:122-134
YAML parser error message leaked to client in handleYamlUpload catch block
The catch block in handleYamlUpload concatenates the raw js-yaml/VM error message into the Error forwarded to the Express error handler, leaking parser internals to the client.
60% - MEDIUMconfirmedover-fetched-response·routes/login.ts:33-47
Login response token embeds full User row (password hash and totpSecret)
The login handler signs the entire authenticated User row — including the password hash and TOTP secret — into the JWT it returns, so any holder of the token can decode those fields.
90% - MEDIUMconfirmedunverified-lookup·routes/order.ts:33-50
Checkout fetches basket by URL id with no ownership check (basket-access IDOR)
POST /rest/basket/:id/checkout fetches the basket using the path id without verifying the authenticated user owns it, letting any logged-in attacker check out another user's basket.
90% - MEDIUMuncertainfile-upload-validation·routes/profileImageFileUpload.ts:16-46
Profile image upload has no file size limit
The profile image upload handler validates MIME via magic number and uses an opaque filename, but enforces no size limit before buffering and writing the file to a publicly served directory.
60% - MEDIUMconfirmedjs-nosql-injection·routes/recycles.ts:12-16
Operator/object injection via JSON.parse() of route parameter into Sequelize where clause
`getRecycleItem` runs `RecycleModel.findAll({ where: { id: JSON.parse(req.params.id) } })`, letting an attacker substitute the scalar id with arbitrary JSON (objects, arrays, operator hashes) and influence the resulting query semantics.
85% - MEDIUMconfirmedweak-password-policy·routes/resetPassword.ts:37-44
Password reset accepts arbitrarily-weak passwords (no length/strength enforcement)
The reset flow writes `req.body.new` to the user record via `user.update({ password: newPassword })` after only checking that the value is non-empty — no minimum length, no complexity rule, no breach/common-password check, and the model's password setter just MD5-hashes whatever it receives.
90% - MEDIUMconfirmedweak-password-reset·routes/securityQuestion.ts:12-28
Security question disclosed to anonymous callers by email lookup
This endpoint returns a user's security question to any unauthenticated caller who supplies the target email, enabling attackers to shop accounts and find easy-to-research questions to abuse in the password reset flow.
90% - MEDIUMconfirmederror-message-leak·routes/updateProductReviews.ts:28-30
Raw error object serialized into 500 response
The MongoDB rejection handler serializes the entire error object directly into the HTTP 500 response, leaking internal database error details to the client.
90% - MEDIUMconfirmedsession-cookie-config·routes/updateUserProfile.ts:40-40
Session 'token' cookie set without HttpOnly, Secure, or SameSite
After updating the user profile, the rotated authentication JWT is written to the 'token' cookie with no options, leaving it readable from JavaScript, transmittable over plaintext HTTP, and sent on cross-site requests.
90% - MEDIUMconfirmedcsrf·routes/updateUserProfile.ts:14-47
CSRF: POST /profile authenticates via cookie and mutates username with no CSRF protection
`POST /profile` reads the session purely from `req.cookies.token` (not the Bearer header) and updates the authenticated user's username, while the application registers no CSRF middleware and the `token` cookie is set without `SameSite=strict`.
90% - MEDIUMconfirmedmissing-security-headers·routes/userProfile.ts:86-96
CSP allows 'unsafe-eval' and is built from user-controlled profileImage
The Content-Security-Policy returned by /profile interpolates the user-controlled profileImage value and explicitly permits 'unsafe-eval' in script-src, defeating the policy and enabling XSS.
95% - MEDIUMconfirmederror-message-leak·routes/vulnCodeSnippet.ts:55-57
Catch blocks return raw error message via utils.getErrorMessage
Both catch blocks in serveCodeSnippet and checkVulnLines return the raw error message to the client via utils.getErrorMessage(error), which extracts err.message and leaks it in the HTTP response body.
55% - MEDIUMconfirmedmissing-access-control·server.ts:358-361
IDOR in GET /api/Users/:id — authenticated user can read any other user's record
The Finale-auto-generated GET /api/Users/:id endpoint is wrapped only with `security.isAuthorized()`; no handler narrows the lookup to the JWT user, so any logged-in account can read any other user's record by enumerating ids.
90% - MEDIUMconfirmedweak-password-reset·server.ts:427-427
Security question exposed to anonymous callers via /rest/user/security-question
The /rest/user/security-question endpoint is mounted without any authentication, letting unauthenticated attackers enumerate the security question chosen by any registered email — the metadata they need to attack the reset flow.
85% - MEDIUMconfirmedhardcoded-secrets·server.ts:267-267
Hardcoded cookie-parser signing secret 'kekse'
The cookie-parser middleware is initialized with a hardcoded signing secret ('kekse') instead of reading it from configuration or an environment variable, exposing the cookie integrity key in source control.
85% - MEDIUMconfirmedmissing-security-headers·server.ts:186-194
No Content-Security-Policy header set on HTML-serving app
The Express app serves HTML (Handlebars views and the Angular client) but only installs helmet.noSniff() and helmet.frameguard() piecemeal — never helmet() as a whole, never helmet.contentSecurityPolicy(), and never a manual Content-Security-Policy header, so responses to browsers have no CSP at all.
90% - MEDIUMconfirmedmissing-security-headers·server.ts:186-194
No Strict-Transport-Security (HSTS) header configured
The Express app never enables helmet's HSTS module (or sets Strict-Transport-Security manually), so browsers will not pin the site to HTTPS, leaving users exposed to SSL-stripping/downgrade attacks on subsequent visits.
85% - LOWconfirmedvulnerable-dependency·frontend/package.json:51-51
Abandoned dependency: `cookieconsent@^3.1.1` (Insites cookieconsent)
`cookieconsent` (Insites/Osano cookieconsent v3) has not received maintenance for years; the upstream project was discontinued and the maintained replacement is `vanilla-cookieconsent` / Osano's commercial product.
60% - LOWconfirmederror-message-leak·routes/likeProductReviews.ts:55-57
Inner catch serializes entire error object in 500 response
The inner catch block returns the raw error object as JSON to the client, leaking internal details from MongoDB driver errors.
85% - LOWconfirmedmissing-security-headers·server.ts:186-194
No Referrer-Policy header configured
The application sets neither helmet.referrerPolicy() nor a manual Referrer-Policy header, so full URLs (including any tokens or sensitive paths embedded in query strings) are leaked in the Referer header when users navigate to third-party origins or load cross-origin resources.
70% - unscoredfalse-positivevulnerable-dependency·frontend/package.json:40-43
End-of-life Font Awesome 5 / `fontawesome-svg-core@~1.2.30`
The Font Awesome 5 line (`@fortawesome/fontawesome-svg-core@~1.2.30` together with `free-*-svg-icons@^5.14.0`) is no longer the supported major; FA6 and FA7 are the maintained lines.
55% - unscoredfalse-positiveerror-message-leak·routes/checkKeys.ts:36-38
Error message leaked via utils.getErrorMessage in nftUnlocked catch block
The nftUnlocked catch block also returns utils.getErrorMessage(error), exposing raw error.message/String(error) content to the client.
50%