agentggagentgg
Back to all findings
MEDIUMconfirmederror-message-leakerror-message-leak6a9e46baf4f4

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.

Fileroutes/checkKeys.ts
Lines2830
Confidence
60%
File statusvalidated
Details

In checkKeys() the catch block returns the result of utils.getErrorMessage(error) directly in the JSON response body:

} catch (error) {
  res.status(500).json(utils.getErrorMessage(error))
}

utils.getErrorMessage in this codebase is a thin wrapper that returns error.message for Error instances and String(error) otherwise — it is not a sanitizer that maps known error classes to user-safe messages. As a result, any unexpected exception thrown inside the handler (e.g., from the dynamic import('ethers'), the HDNodeWallet.fromPhrase call, or downstream code) surfaces its raw message — including module paths or library-internal error strings — to the HTTP client. This matches the rule's true-positive criteria: a catch (err) in an HTTP route handler where the response body includes err.message / String(err).

Proof of concept
  1. Send a malformed request to the route bound to checkKeys that triggers an exception inside the try block (e.g., cause HDNodeWallet.fromPhrase or an internal call to throw).
  2. Observe the 500 response body — it contains the raw underlying error message instead of a generic message like { error: "internal server error" }.
Impact

Unauthenticated attackers probing the endpoint can fingerprint internal library behavior, file/module identifiers, and other implementation details from raw error text, aiding further attacks.

Validation
confirmed

The catch block at lines 28-30 literally executes res.status(500).json(utils.getErrorMessage(error)), returning the raw error message to the HTTP client. utils.getErrorMessage in the Juice Shop codebase returns error.message for Error instances, which is not sanitization. Any unexpected exception from HDNodeWallet.fromPhrase or the dynamic import('ethers') would surface internal details to an unauthenticated caller, matching the error-message-leak pattern. The exploit is reachable from untrusted input via the route handler.

CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Base score: 5.3 · MEDIUM

The checkKeys route is an HTTP endpoint with no visible authentication middleware, so an unauthenticated remote attacker can reach the catch block by sending a malformed body that triggers exceptions in HDNodeWallet.fromPhrase or the dynamic import('ethers'). The sink (res.status(500).json(utils.getErrorMessage(error))) leaks raw error.message / String(error) strings, giving the attacker partial, low-control disclosure of internal library/module details (Confidentiality: Low). There is no write path or DoS introduced by this bug, so Integrity and Availability are None, and the leak stays within the same component (Scope: Unchanged).

References