Insecure default value for JWT secret
Description
The custodial wallet uses JSON Web Tokens (JWTs) to authenticate a user to the backend. To prevent a malicious user from tampering with the contents of the JWTs, a secret only known to the server is used to sign the token.
import * as env from 'env-var'
export const ENV_NAME = env.get('ENV_NAME').required().asString()
export const BROKER_URL = env.get('BROKER_URL').required().asUrlString()
export const HTTP_PORT = env.get('HTTP_PORT').required().asPortNumber()
export const SERVICE_NAME = env.get('K_SERVICE').required().asString()
export const CLIENT_JWT_SECRET = env
.get('CLIENT_JWT_SECRET')
.default('sekret')
.asString();
export const WALLET_API_KMS_ID = env.get('WALLET_API_KMS_ID').required().asString()
export const INFURA_API_KEY = env.get('INFURA_API_KEY').required().asString()
export const STATSIG_SERVER_KEY = env.get('STATSIG_SERVER_KEY').required().asString()
The code uses the env-var
package to dynamically pull secrets from environment variables. In case the CLIENT_JWT_SECRET
is not set, it will default to an easily guessable string --- sekret
.
Impact
An easily guessed JWT secret would allow an attacker to sign tokens with arbitrary data, for example an admin email address. A valid JWT with an admin email address would let the attacker call any function with any parameters, thus affecting all custodial wallets.
Recommendations
In an ideal case, the .required()
method should be used; this forces the environment variable to be present and would throw an error if it is missing. If a default fallback value has to be used, it should be replaced with a strong, randomly generated string that is highly secure and cannot be guessed or bruteforced.
Remediation
This issue has been acknowledged by LootRush, and a fix was implemented in commit a90348f9↗.