Path Traversal with Jwt Tokens
How Path Traversal Manifests in Jwt Tokens
Path traversal vulnerabilities in JWT implementations occur when token claims or payload data are used to construct filesystem paths without proper validation. This attack pattern allows adversaries to access files outside intended directories by manipulating path components.
Common Jwt Tokens-specific manifestations include:
- Using JWT claims as dynamic path components in file operations
- Constructing database queries or API endpoints from token data
- Exposing file paths in JWT payloads that attackers can manipulate
Consider this vulnerable Jwt Tokens pattern:
import jwt
from flask import request, send_file
SECRET_KEY = 'mysecret'
@app.route('/download')
def download_file():
token = request.headers.get('Authorization').split(' ')[1]
data = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
# VULNERABLE: user-controlled claim used directly in path
file_path = f"/var/app/uploads/{data['filename']}"
return send_file(file_path)
An attacker can craft a token with filename=../../etc/passwd to traverse outside the uploads directory. The JWT signature validation passes, but the application logic fails to validate the path content.
Another Jwt Tokens-specific pattern involves using tokens for database path resolution:
const jwt = require('jsonwebtoken');
app.get('/data/:id', (req, res) => {
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// VULNERABLE: claim used to construct database path
const collection = decoded.role + '/' + req.params.id;
db.collection(collection).find().toArray((err, docs) => {
res.json(docs);
});
Here, a user with role admin could access admin/../user/123, potentially bypassing authorization checks.
Path traversal in JWT contexts often combines with other vulnerabilities. For example, a JWT containing ../ sequences might bypass authorization when combined with case-insensitive filesystems or Windows path handling.
Jwt Tokens-Specific Detection
Detecting path traversal in JWT implementations requires examining both the token validation logic and how token claims are used in path construction. Key detection strategies include:
- Claim content analysis: Scan for claims that contain filesystem paths, URLs, or identifiers that could be used in path construction
- Path construction patterns: Identify code that concatenates token claims with directory paths
- Input validation gaps: Look for missing validation on claims used in file operations
middleBrick's Jwt Tokens-specific scanning identifies these patterns through:
- Static analysis of JWT claim usage in path construction
- Dynamic testing with crafted tokens containing path traversal sequences
- Cross-referencing OpenAPI specs to identify path parameters derived from JWT claims
Manual detection checklist for Jwt Tokens implementations:
# Check for vulnerable patterns
grep -r "jwt\.decode\|jwt\.verify" . --include="*.py" --include="*.js" --include="*.ts" |
while read -r file; do
grep -E "(path|filename|filepath|url|directory)" "$file" | grep -v "validate" | head -5
done
Look for these Jwt Tokens-specific red flags:
| Pattern | Risk Level | Detection Method |
|---|---|---|
| Claims used in file paths without validation | High | Static code analysis |
| Dynamic database collection names from JWT claims | High | Runtime monitoring |
| URL construction from token data | Medium | Input validation testing |
| Case-insensitive path comparisons | Medium | Platform-specific testing |
For comprehensive Jwt Tokens security assessment, middleBrick scans unauthenticated endpoints and analyzes how JWT claims flow through the application, identifying path traversal opportunities that manual review might miss.
Jwt Tokens-Specific Remediation
Remediating path traversal in JWT implementations requires both input validation and secure path handling practices. Here are Jwt Tokens-specific fixes:
1. Input Validation and Sanitization
import jwt
import re
from flask import request, send_file
def validate_filename(filename):
# Allow only alphanumeric, hyphen, underscore, and dot
if not re.match(r'^[a-zA-Z0-9._-]+$', filename):
raise ValueError('Invalid filename')
# Prevent directory traversal
if '..' in filename or filename.startswith('/') or filename.startswith('\\'):
raise ValueError('Path traversal detected')
return filename
SECRET_KEY = 'mysecret'
@app.route('/download')
def download_file():
token = request.headers.get('Authorization').split(' ')[1]
data = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
try:
safe_filename = validate_filename(data['filename'])
file_path = f"/var/app/uploads/{safe_filename}"
return send_file(file_path)
except ValueError as e:
return {'error': str(e)}, 400
2. Canonical Path Resolution
const jwt = require('jsonwebtoken');
const path = require('path');
function safeFilePath(baseDir, filename) {
const fullPath = path.join(baseDir, filename);
const resolvedPath = path.resolve(fullPath);
// Ensure resolved path starts with base directory
if (!resolvedPath.startsWith(baseDir)) {
throw new Error('Path traversal detected');
}
return resolvedPath;
app.get('/download', (req, res) => {
const token = req.headers.authorization.split(' ')[1];
try {
const safePath = safeFilePath('/var/app/uploads', decoded.filename);
} catch (err) {
res.status(400).json({error: 'Invalid file request'});
}
3. Claim Whitelisting and Normalization
package main
import (
"encoding/json"
"errors"
"net/http"
"path/filepath"
"github.com/golang-jwt/jwt/v5"
)
func validateAndResolvePath(claims jwt.MapClaims, filename string) (string, error) {
// Normalize and validate filename
cleanName := filepath.Base(filename)
if cleanName != filename {
return "", errors.New("invalid filename format")
}
// Construct safe path
baseDir := "/var/app/uploads"
fullPath := filepath.Join(baseDir, cleanName)
// Verify path is within base directory
if !strings.HasPrefix(filepath.Clean(fullPath), filepath.Clean(baseDir)) {
return "", errors.New("path traversal detected")
}
return fullPath, nil
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")[7:] // strip "Bearer "
return []byte("mysecret"), nil
})
if err != nil {
http.Error(w, "invalid token", 401)
}
filename := claims.(jwt.MapClaims)["filename"].(string)
if err != nil {
http.Error(w, err.Error(), 400)
}
http.ServeFile(w, r, safePath)
}
Additional Jwt Tokens-specific hardening:
- Use signed claims with limited character sets (alphanumeric only)
- Implement claim value length limits
- Log and monitor for path traversal attempts
- Consider using claim IDs instead of raw paths
middleBrick's remediation guidance includes specific code examples for your framework and provides severity-based prioritization of findings, helping you address the most critical path traversal vulnerabilities first.
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 |