Path Traversal with Bearer Tokens
How Path Traversal Manifests in Bearer Tokens
Path traversal vulnerabilities in Bearer Token implementations occur when unvalidated user input containing directory traversal sequences (like ../) is used to construct file paths or access resources. In Bearer Token contexts, this often appears when tokens are used to authorize access to file-based resources or when token claims contain filesystem paths.
A common manifestation is in API endpoints that use Bearer Token claims to determine which user files to access. For example, a token might contain a userId claim that's used to construct a file path like /data/users/{userId}/profile.json. If an attacker can manipulate this claim to include traversal sequences, they could access files outside the intended directory.
const jwt = require('jsonwebtoken');
const fs = require('fs');
// Vulnerable implementation
function getUserProfile(req, res) {
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Path traversal vulnerability: userId can contain '../' sequences
const filePath = `/data/users/${decoded.userId}/profile.json`;
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) return res.status(404).send('Profile not found');
res.json(JSON.parse(data));
});
}
In this example, if an attacker crafts a token with userId set to ../admin, the resulting path becomes /data/users/../admin/profile.json, which resolves to /data/admin/profile.json, potentially exposing admin data.
Another Bearer Token-specific scenario involves path traversal in token revocation lists or blacklist files. Some systems store revoked tokens in files named after the token hash, and if the hash input isn't properly sanitized, traversal attacks become possible.
function isTokenRevoked(tokenHash) {
// Vulnerable: tokenHash could contain path traversal
const blacklistPath = `/var/token-blacklist/${tokenHash}.json`;
try {
const stats = fs.statSync(blacklistPath);
return stats.isFile();
} catch (err) {
return false;
}
}
Attackers could craft token hashes containing ../ to check for the existence of arbitrary files on the server, potentially leaking sensitive information through timing differences or error messages.
Bearer Tokens-Specific Detection
Detecting path traversal in Bearer Token implementations requires both static analysis and dynamic testing. Static analysis tools should scan for filesystem operations where paths are constructed from token claims or properties.
Key detection patterns include:
- Filesystem operations (
fs.readFile,fs.readFileSync, etc.) where paths contain token-derived variables - Database queries using token claims in LIKE clauses or path-like patterns
- URL construction for file downloads where token claims form part of the path
- Archive extraction operations using token-derived paths
Dynamic testing with tools like middleBrick can automatically detect these vulnerabilities by scanning API endpoints that accept Bearer Tokens. The scanner tests for common traversal patterns including:
../ (dot-dot-slash)
..\ (dot-dot-backslash)
/ (forward slash)
\ (backslash)
%2e%2e%2f (URL-encoded traversal)
%2e%2e/ (mixed encoding)
middleBrick's Bearer Token-specific scanning includes testing for traversal in JWT claims by crafting tokens with malicious payloads and observing how the server handles them. The scanner checks if tokens containing traversal sequences in standard claims like sub, aud, or custom claims are properly rejected or if they lead to unauthorized file access.
For comprehensive detection, implement runtime monitoring that logs and alerts on:
const path = require('path');
function safeFilePath(baseDir, relativePath) {
const resolved = path.resolve(baseDir, relativePath);
if (!resolved.startsWith(baseDir)) {
console.warn('Potential path traversal attempt:', relativePath);
throw new Error('Invalid path');
}
return resolved;
}
This monitoring can detect when token claims or other input attempts to escape the intended directory structure, providing early warning of traversal attempts.
Bearer Tokens-Specific Remediation
Remediating path traversal in Bearer Token implementations requires a defense-in-depth approach. The most effective strategy combines input validation, path normalization, and secure coding practices.
First, always validate and sanitize token claims before using them in file paths. For numeric IDs like userId, ensure they're actual numbers:
function validateUserId(userId) {
const num = Number(userId);
if (!Number.isInteger(num) || num <= 0) {
throw new Error('Invalid user ID format');
}
return num;
}
// Secure implementation
function getUserProfile(req, res) {
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
try {
const userId = validateUserId(decoded.userId);
const filePath = path.join('/data/users', String(userId), 'profile.json');
// Additional safety: check if file exists within allowed directory
const resolved = path.resolve(filePath);
if (!resolved.startsWith('/data/users')) {
return res.status(400).send('Invalid path');
}
fs.readFile(resolved, 'utf8', (err, data) => {
if (err) return res.status(404).send('Profile not found');
res.json(JSON.parse(data));
});
} catch (err) {
res.status(400).send('Invalid token or user ID');
}
}
For string-based paths or identifiers, use strict whitelisting or encoding:
function sanitizePathSegment(segment) {
// Allow only alphanumeric, hyphen, underscore
if (!/^[a-zA-Z0-9_-]+$/.test(segment)) {
throw new Error('Invalid path segment');
}
return segment;
}
// For token hashes or other sensitive identifiers
function safeTokenHashPath(tokenHash) {
// Hash-based tokens should use only hex characters
if (!/^[a-f0-9]{32,128}$/i.test(tokenHash)) {
throw new Error('Invalid token hash format');
}
return path.join('/var/token-blacklist', tokenHash + '.json');
}
Implement a centralized path validation utility:
const path = require('path');
class PathValidator {
constructor(baseDir) {
this.baseDir = path.resolve(baseDir);
}
validate(filePath) {
const resolved = path.resolve(this.baseDir, filePath);
if (!resolved.startsWith(this.baseDir)) {
throw new Error('Path traversal detected');
}
return resolved;
}
validateTokenClaim(claimValue, claimName) {
// Different validation based on claim type
if (claimName === 'userId') {
return this.validate(String(validateUserId(claimValue)));
} else if (claimName === 'username') {
return this.validate(sanitizePathSegment(claimValue));
}
// Default: reject any non-alphanumeric claims used in paths
if (!/^[a-zA-Z0-9]+$/.test(claimValue)) {
throw new Error(`Invalid ${claimName} for path construction`);
}
return this.validate(claimValue);
}
}
Finally, use principle of least privilege for file system access. If your application only needs read access to specific files, configure the system to enforce these permissions at the OS level, making traversal attacks less impactful even if they occur.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |
Frequently Asked Questions
How can I test my Bearer Token implementation for path traversal vulnerabilities?
../, ..\, and URL-encoded traversal sequences. Monitor how your server constructs file paths from these claims and whether it properly validates or rejects them.