HIGH information disclosurejwt tokens

Information Disclosure with Jwt Tokens

How Information Disclosure Manifests in Jwt Tokens

Information disclosure in JWT tokens occurs when sensitive data is encoded in the token payload without proper protection, allowing attackers to extract valuable information through simple base64 decoding. Unlike encryption, JWT signing only provides integrity verification, not confidentiality. This means anyone can decode a JWT token and read its contents, making it critical to never include sensitive information in the payload.

A common vulnerability appears when developers include user email addresses, phone numbers, or internal identifiers directly in the JWT payload. For example:

// VULNERABLE: Exposes user email in token payload
const token = jwt.sign({
  userId: user.id,           // internal database ID
  email: user.email,         // PII exposure
  role: user.role,           // may reveal internal structure
  issuedAt: Date.now()
}, process.env.JWT_SECRET);

Attackers can extract this information by decoding the token:

# Extract payload from JWT
JWT="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjMiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwicm9sZSI6ImFkbWluIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
PAYLOAD=$(echo $JWT | cut -d'.' -f2)
echo $PAYLOAD | base64 -d
# Outputs: {"userId":"123","email":"[email protected]","role":"admin"}

Another manifestation involves excessive claims that reveal system architecture. Including database table names, internal service identifiers, or implementation details in tokens provides attackers with reconnaissance data. For instance, tokens containing "tenantId" or "departmentCode" can help map organizational structure.

Misconfigured JWT libraries can also lead to information disclosure through default claims. Some implementations automatically include "iat" (issued at), "exp" (expiration), and "nbf" (not before) timestamps, which may reveal system uptime patterns or token rotation schedules that assist timing-based attacks.

Publicly accessible endpoints that return JWT tokens in responses without proper access controls create additional disclosure risks. If an authentication endpoint returns tokens in plaintext HTTP responses or logs them in server logs, sensitive session data becomes exposed to network sniffers and log analysis tools.

Jwt Tokens-Specific Detection

Detecting information disclosure in JWT tokens requires analyzing both the token structure and the application's token generation logic. Static analysis tools can identify hardcoded secrets and sensitive data patterns in token payloads, while dynamic scanning examines runtime token behavior.

middleBrick's JWT-specific scanning examines tokens across multiple dimensions:

Payload Analysis: The scanner decodes JWT tokens and analyzes payload contents against 27 regex patterns for sensitive data including PII, API keys, and system identifiers. It flags tokens containing email addresses, phone numbers, social security numbers, credit card numbers, and internal database IDs.

Claim Auditing: middleBrick checks for excessive or unnecessary claims that reveal system architecture. It identifies tokens with internal identifiers like "tenantId", "departmentCode", or database-specific references that shouldn't be exposed to clients.

Algorithm Verification: The scanner verifies JWT algorithms are configured securely. It flags the use of "none" algorithm (which provides no integrity protection) and warns about weak signing algorithms like HS256 with insufficient key lengths.

Transport Security: middleBrick checks whether tokens are transmitted over secure channels. It identifies JWTs sent over HTTP instead of HTTPS, tokens included in URLs (vulnerable to browser history and referrer leakage), and tokens stored insecurely in client-side storage.

Expiration Analysis: The scanner evaluates token expiration policies. Tokens with excessively long lifetimes (years instead of minutes or hours) increase the window for information disclosure if tokens are compromised.

Manual detection techniques include:

# Decode and inspect JWT token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
echo $TOKEN | cut -d'.' -f2 | base64 -d
# Look for sensitive data patterns
TOKEN_PAYLOAD=$(echo $TOKEN | cut -d'.' -f2 | base64 -d)
echo $TOKEN_PAYLOAD | grep -E "(email|phone|ssn|credit|password|secret|key)"

Network traffic analysis can reveal tokens transmitted insecurely. Tools like Wireshark or browser developer tools can capture JWTs in transit, exposing whether they're properly encrypted and transmitted over HTTPS.

Jwt Tokens-Specific Remediation

Remediating JWT information disclosure requires architectural changes to token design and strict adherence to security best practices. The fundamental principle is to minimize the information included in JWT payloads.

Minimal Payload Design: Only include essential identifiers in JWT tokens. Use opaque references instead of actual data:

// SECURE: Minimal payload with opaque reference
const token = jwt.sign({
  sub: user.id,           // Only user ID
  role: user.role,        // Minimal authorization data
  iat: Math.floor(Date.now() / 1000)
}, process.env.JWT_SECRET, { expiresIn: '15m' });

// Store sensitive data server-side and reference by ID
app.get('/user/profile', authenticate, (req, res) => {
  const userId = req.user.sub;
  db.getUserProfile(userId)
    .then(profile => res.json(profile))
    .catch(err => res.status(500).json({ error: 'Internal error' }));
});

Database Reference Pattern: Store sensitive user data in server-side databases and use token IDs to reference it:

// Generate token with minimal data
const token = jwt.sign({
  userId: user.id,
  tokenId: generateTokenId() // Opaque reference
}, process.env.JWT_SECRET);

// Store extended data server-side
const tokenData = {
  userId: user.id,
  email: user.email,
  permissions: user.permissions,
  issuedAt: new Date()
};
db.saveTokenData(tokenData.tokenId, tokenData);

Secure Transmission: Always use HTTPS for JWT transmission and avoid including tokens in URLs:

// SECURE: Use HTTPS and secure headers
app.post('/login', (req, res) => {
  // Authenticate user
  const token = generateSecureToken(user);
  
  // Set secure cookie with HTTP-only flag
  res.cookie('jwt', token, {
    httpOnly: true,
    secure: true,        // Only over HTTPS
    sameSite: 'strict',
    maxAge: 15 * 60 * 1000 // 15 minutes
  });
  
  res.json({ success: true });
});

Algorithm and Key Management: Use strong algorithms and proper key management:

// SECURE: Strong algorithm configuration
const token = jwt.sign(payload, process.env.JWT_SECRET, {
  algorithm: 'RS256',          // Asymmetric for better security
  expiresIn: '15m',            // Short lifetime
  issuer: 'your-app.com',
  audience: 'your-app.com'
});

// Verify with proper options
jwt.verify(token, process.env.JWT_SECRET, {
  algorithms: ['RS256'],
  issuer: 'your-app.com',
  audience: 'your-app.com'
});

Input Validation: Validate all data before including it in tokens:

// SECURE: Validate and sanitize payload data
function createSecureToken(user) {
  if (!user || !user.id || !user.role) {
    throw new Error('Invalid user data for token');
  }
  
  const sanitizedUser = {
    id: user.id.toString(),  // Ensure consistent type
    role: user.role.trim()   // Remove whitespace
  };
  
  return jwt.sign({
    sub: sanitizedUser.id,
    role: sanitizedUser.role,
    iat: Math.floor(Date.now() / 1000)
  }, process.env.JWT_SECRET, { expiresIn: '15m' });
}

Logging and Monitoring: Implement proper logging to detect information disclosure attempts:

// Monitor for suspicious token patterns
app.use((req, res, next) => {
  if (req.headers.authorization) {
    const token = req.headers.authorization.replace('Bearer ', '');
    try {
      const decoded = jwt.decode(token);
      if (decoded && decoded.email) {
        console.warn('Token contains email address:', decoded.email);
      }
    } catch (err) {
      // Invalid token format - log for analysis
      console.debug('Malformed token detected:', token.substring(0, 20));
    }
  }
  next();
});

Frequently Asked Questions

Can JWT tokens be encrypted to prevent information disclosure?
Standard JWT tokens are signed but not encrypted - the payload is base64 encoded but readable. For true confidentiality, use JWE (JSON Web Encryption) or encrypt sensitive data before including it in the JWT payload. However, the best practice is to avoid including sensitive data in tokens entirely and use server-side storage with token references.
How does middleBrick detect information disclosure in JWT tokens?
middleBrick decodes JWT tokens and analyzes the payload contents against 27 regex patterns for sensitive data including PII, API keys, and internal identifiers. It flags tokens containing email addresses, phone numbers, social security numbers, credit card numbers, and internal database IDs. The scanner also checks for excessive claims that reveal system architecture and verifies secure transmission practices.