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.
The handler accepts an email from req.query, looks up the associated SecurityAnswerModel (joined to the user), and returns the resolved SecurityQuestionModel row as JSON. There is no authentication, no rate limiting, and no per-account lockout. Any anonymous client can iterate over candidate emails and learn each user's security question text.
const email = query.email
const answer = await SecurityAnswerModel.findOne({
include: [{ model: UserModel, where: { email: email?.toString() } }]
})
if (answer != null) {
const question = await SecurityQuestionModel.findByPk(answer.SecurityQuestionId)
res.json({ question })
}
Per the detection brief, this is explicitly called out as a red flag: "Endpoints that return the security question text to anonymous callers (lets attackers shop accounts to find easy questions)." In Juice-Shop the security question/answer is the sole knowledge factor used by the reset flow (/rest/user/reset-password), so disclosure of the question directly enables targeted social-engineering / OSINT against the answer (mother's maiden name, pet's name, hometown, etc.).
Additionally, because the lookup answers truthfully or returns {}, the endpoint doubles as a user-existence oracle (returns a populated question when the email is registered, empty object otherwise).
- As an unauthenticated attacker, send:
GET /rest/user/security-question?email=victim@example.com. - Observe the JSON body — it contains the security question text bound to that account (e.g. "Name of your favorite pet?").
- Mine public sources (social media, breached profile data) for the likely answer.
- Submit the answer + a new password to the security-answer-based reset endpoint to take over the account.
- Repeat step 1 against a list of emails to identify (a) which addresses are registered (presence/absence of
questionfield) and (b) which accounts use the weakest/most-researchable questions.
Any unauthenticated attacker can enumerate registered accounts and learn each user's security question, materially lowering the cost of guessing the security answer that gates the password reset flow. Combined with the security-question-only reset, this leads to full account takeover with no email round-trip required. It also leaks account-existence (presence of question), enabling targeted phishing.
The handler in securityQuestion() reads query.email with no authentication or rate-limiting middleware, performs a SecurityAnswerModel.findOne joined to UserModel by email, and returns the resolved SecurityQuestionModel row via res.json({ question }). An anonymous attacker can enumerate emails and harvest each victim's security question text, then use it against Juice Shop's security-answer-based reset flow. The res.json({}) fallback also distinguishes registered vs unregistered emails, providing an account-existence oracle. The PoC is directly reachable from untrusted input.
The securityQuestion() handler reads query.email and returns the matching SecurityQuestionModel to any caller without checking authentication, session, or rate-limiting, so AV:N/AC:L/PR:N/UI:N is straightforward — a remote anonymous attacker hits GET /rest/user/security-question?email=... directly. The disclosed data is bounded (the question text plus account-existence via populated vs {} response), so confidentiality is L rather than H — the attacker doesn't get arbitrary records, only the question and registration status for emails they already know/guess. The endpoint itself does not write state (I:N) nor degrade availability (A:N); the downstream account-takeover risk through /rest/user/reset-password would be scored against that reset endpoint, and the disclosure stays within the application's security authority so Scope is Unchanged.
- CWE-640: Weak Password Recovery Mechanism for Forgotten Password
- CWE-203: Observable Discrepancy
- OWASP ASVS V2.5 Credential Recovery
- https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html