agentggagentgg
Back to all findings
unscoredfalse-positiveerror-message-leakerror-message-leakcb274886ab16

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.

Fileroutes/checkKeys.ts
Lines3638
Confidence
50%
File statusvalidated
Details

In nftUnlocked() the catch block mirrors the same pattern:

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

utils.getErrorMessage returns the raw error.message (or String(error)) rather than translating known error classes into a user-safe message. Any thrown exception during the handler will leak that raw text in the 500 response body, satisfying the rule's true-positive criteria for an HTTP catch block returning err.message / String(err).

Proof of concept
  1. Force an exception in the nftUnlocked handler (for example, by causing a property access on challenges.nftUnlockChallenge to throw).
  2. The 500 response body contains the raw error text returned by getErrorMessage, rather than a static sanitized message.
Impact

Allows unauthenticated clients to harvest raw exception text from the server, which can disclose internal implementation details useful for reconnaissance.

Validation
false-positive

The nftUnlocked try block only executes res.status(200).json({ status: challenges.nftUnlockChallenge.solved }) — there is no user-controlled input (no req.body/query/params usage) that an attacker could manipulate to force the catch branch. The detector's PoC ("cause a property access on challenges.nftUnlockChallenge to throw") relies on server-side state being broken, which is not an attacker-reachable condition. While utils.getErrorMessage is suboptimal in principle, the catch here is effectively unreachable from untrusted input, so there is no exploitable disclosure.

References