Replay Attack with Jwt Tokens
How Replay Attack Manifests in Jwt Tokens
Replay attacks in JWT tokens occur when an attacker intercepts a valid token and uses it to impersonate the legitimate user without needing to compromise the token's cryptographic signature. This attack vector is particularly dangerous because the intercepted JWT appears completely valid to the receiving server.
// Intercepted JWT token from network traffic or XSS attack
const stolenJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6InN1cGVydXNlciIsImlhdCI6MTY0MjE5MDI0NX0.fakeSignature';
// Attacker uses the stolen token
fetch('https://api.example.com/protected', {
headers: {
'Authorization': `Bearer ${stolenJwt}`
}
});
The core vulnerability stems from JWT tokens lacking built-in expiration enforcement mechanisms. While JWTs contain an exp claim for expiration, servers must explicitly validate this claim. Many implementations fail to check expiration, allowing indefinitely valid tokens.
// VULNERABLE: Missing expiration check
const token = jwt.verify(req.headers.authorization.split(' ')[1], secret); // No exp validation
// Attacker can replay this token anytime
Replay attacks become more severe when combined with JWT's stateless nature. Unlike session-based authentication where servers can maintain token revocation lists, JWT tokens cannot be invalidated once issued without additional infrastructure.
// No built-in revocation mechanism
// Once issued, JWT remains valid until expiration
const validJwt = jwt.sign({
userId: '123',
role: 'admin'
}, process.env.JWT_SECRET, { expiresIn: '1h' });
// Attacker steals this token and uses it within 1 hour
Network-level vulnerabilities amplify replay attack risks. JWT tokens transmitted over HTTP can be captured via man-in-the-middle attacks, packet sniffing, or through browser storage compromise (localStorage, sessionStorage).
// Vulnerable storage - XSS can steal tokens
localStorage.setItem('jwt_token', validJwt);
// Attacker uses XSS to retrieve and replay
Jwt Tokens-Specific Detection
Detecting replay attack vulnerabilities in JWT implementations requires examining both token validation logic and transmission security. middleBrick's JWT-specific scanner identifies these patterns across 12 security checks.
| Detection Method | Implementation Check | Risk Level |
|---|---|---|
| Expiration Validation | Verifies exp claim is checked during token verification | High |
| Secure Transmission | Ensures HTTPS-only JWT transmission | Critical |
| Storage Security | Checks for unsafe JWT storage (localStorage, cookies without HttpOnly) | High |
| Token Rotation | Detects absence of refresh token mechanisms | Medium |
| Revocation Support | Identifies lack of token blacklisting capability | Medium |
middleBrick's active scanning tests JWT endpoints by attempting replay attacks with captured tokens. The scanner verifies whether servers properly validate token expiration and reject replayed tokens.
# middleBrick CLI scan for JWT replay vulnerabilities
middlebrick scan https://api.example.com/auth
# Output includes JWT-specific findings:
# - Missing expiration validation
# - Insecure token storage detected
# - No refresh token implementation
# - Weak token rotation strategy
The scanner also examines OpenAPI specifications for JWT-related endpoints, checking for proper security scheme definitions and validation requirements.
# OpenAPI spec analysis for JWT security
security:
- BearerAuth: []
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
middleBrick's LLM security checks extend to AI-powered JWT implementations, detecting prompt injection vulnerabilities that could expose token generation logic or secret keys.
Jwt Tokens-Specific Remediation
Securing JWT implementations against replay attacks requires multiple defensive layers. The most critical remediation is proper expiration validation with minimal token lifetimes.
// SECURE: Short-lived JWT with strict expiration
const jwt = require('jsonwebtoken');
function generateSecureJwt(payload) {
return jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: '15m', // Short lifetime reduces replay window
issuer: 'your-domain.com',
audience: 'your-api'
});
}
// Always validate expiration on verification
function verifyJwt(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET, {
maxAge: '15m', // Enforce strict expiration
issuer: 'your-domain.com',
audience: 'your-api'
});
} catch (error) {
// Handle expired, invalid, or replayed tokens
if (error.name === 'TokenExpiredError') {
throw new Error('Token expired');
}
throw new Error('Invalid token');
}
}
Implement refresh token mechanisms to maintain user sessions while minimizing replay attack windows for access tokens.
// Refresh token pattern - rotate access tokens
const refreshTokens = new Map();
async function login(username, password) {
const user = await authenticateUser(username, password);
// Short-lived access token
const accessToken = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
// Long-lived refresh token (secure storage only)
const refreshToken = jwt.sign(
{ userId: user.id, version: user.tokenVersion },
process.env.REFRESH_SECRET,
{ expiresIn: '7d' }
);
refreshTokens.set(refreshToken, user.id);
return { accessToken, refreshToken };
}
async function refreshAccessToken(refreshToken) {
if (!refreshTokens.has(refreshToken)) {
throw new Error('Invalid refresh token');
}
const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
const user = await getUserById(decoded.userId);
// Check if user's token was invalidated
if (user.tokenVersion !== decoded.version) {
throw new Error('Token version mismatch');
}
return generateSecureJwt({ userId: user.id, role: user.role });
}
Enforce HTTPS-only transmission and secure storage practices to prevent token interception.
// Secure JWT handling
// 1. Always use HTTPS
// 2. Store refresh tokens in HttpOnly cookies
// 3. Never store access tokens in localStorage
// 4. Implement token rotation
// 5. Use SameSite cookies for refresh tokens
// HttpOnly cookie for refresh token
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
middleBrick's Pro plan includes continuous monitoring that automatically scans your JWT endpoints for replay attack vulnerabilities, alerting you when security scores drop below configured thresholds.