Jwt Misconfiguration in Express with Hmac Signatures
Jwt Misconfiguration in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability
JSON Web Tokens (JWT) with HMAC signatures (typically HS256) are widely used in Express APIs for stateless authentication. When misconfigured, this combination can lead to token forgery, algorithm confusion, or secret leakage, enabling attackers to impersonate users or escalate privileges.
One common misconfiguration is accepting tokens without validating the algorithm, which allows an attacker to change the alg header to none or to a weaker algorithm like HS256 when the server expects RSA-based verification. If the application uses a weak or leaked shared secret, the signature becomes trivial to brute-force, undermining integrity. An attacker can also tamper with claims such as role or exp if the token is not validated for expected issuer (iss), audience (aud), and expiration.
Another specific risk in Express is improper secret management. Hardcoding secrets in source code or using environment variables that are exposed in logs or error messages can lead to secret discovery. If the same secret is used across multiple services or applications, a compromise of one service can affect others. Additionally, failing to verify token structure and required claims can result in accepting unsigned tokens or tokens with missing fields, which may bypass intended authorization checks.
Middleware choices and configuration further influence risk. Using a permissive JWT verification library or incorrect options can skip critical validation steps. For example, not setting requireSigned: true (where applicable) or not specifying allowed algorithms can open the door to substitution attacks. Inconsistent handling of token revocation and lack of proper token binding can also allow replay attacks even when signatures are valid.
These issues are detectable by middleBrick's Authentication and BOLA/IDOR checks, which analyze endpoint behavior and token handling without authentication. The LLM/AI Security module looks for insecure patterns in API configurations and error messages that might leak secrets or hint at weak validation, while the Input Validation and Data Exposure checks identify endpoints that accept or return tokens in an unsafe manner.
Hmac Signatures-Specific Remediation in Express — concrete code fixes
To secure JWTs with HMAC in Express, enforce strict algorithm validation, use strong secrets, and validate all standard claims. Below are concrete, secure examples using the jsonwebtoken library.
Secure Token Verification with Explicit Algorithm
Always specify allowed algorithms and avoid relying on library defaults. Use an array with only the intended algorithm.
const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();
const SECRET = process.env.JWT_SECRET; // Must be a strong, sufficiently long random string
const ALLOWED_ALGORITHMS = ['HS256'];
function verifyToken(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
const token = authHeader.split(' ')[1];
jwt.verify(token, SECRET, { algorithms: ALLOWED_ALGORITHMS }, (err, decoded) => {
if (err) {
return res.status(401).json({ error: 'Invalid token' });
}
// Enforce expected claims
if (!decoded.iss || decoded.iss !== 'myapi.example.com') {
return res.status(401).json({ error: 'Invalid issuer' });
}
if (!decoded.aud || decoded.aud !== 'myapp') {
return res.status(401).json({ error: 'Invalid audience' });
}
if (decoded.exp <= Math.floor(Date.now() / 1000)) {
return res.status(401).json({ error: 'Token expired' });
}
req.user = decoded;
next();
});
}
app.get('/profile', verifyToken, (req, res) => {
res.json({ user: req.user.sub });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Signing Tokens with Explicit Algorithm and Claims
When issuing tokens, explicitly set the algorithm and include necessary claims to prevent ambiguity and enforce policy.
const jwt = require('jsonwebtoken');
function generateToken(payload) {
return jwt.sign(
{
sub: payload.userId,
iss: 'myapi.example.com',
aud: 'myapp',
role: payload.role || 'user',
},
process.env.JWT_SECRET,
{
algorithm: 'HS256',
expiresIn: '15m',
notBefore: '0',
}
);
}
// Example usage
const token = generateToken({ userId: 'u123', role: 'admin' });
console.log(token);
Operational and Configuration Best Practices
- Store secrets in a secure environment or secret manager; never hardcode or commit them to version control.
- Rotate secrets periodically and have a plan for key revocation if a secret is compromised.
- Validate all token claims on every request, including
iss,aud,exp, andnbf. - Use HTTPS to prevent token interception; set the
secureflag for cookies if storing tokens there. - Implement short token lifetimes and use refresh tokens with strict binding and revocation mechanisms.
- Log validation failures securely without exposing token content or secrets in logs or error messages.
middleBrick's GitHub Action can be added to CI/CD pipelines to fail builds if a scanned API's risk score drops below your defined threshold, helping to catch insecure JWT configurations before deployment. The CLI tool (middlebrick scan <url>) allows you to validate endpoints from the terminal, while the MCP Server enables scanning directly from AI coding assistants in your IDE.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |