Password Spraying with Bearer Tokens
How Password Spraying Manifests in Bearer Tokens
Password spraying with Bearer tokens exploits the fundamental trust model of token-based authentication. Unlike traditional password spraying where attackers try common passwords across many accounts, Bearer token spraying targets the token validation mechanism itself.
The attack typically begins with an attacker obtaining a valid token through various means—phishing, network interception, or purchasing from dark markets. The attacker then systematically tests this token against numerous API endpoints to map out functionality and identify privileged operations. Since Bearer tokens are often scoped too broadly, a single token might grant access to administrative functions, user data modification, or system configuration.
A common manifestation involves automated scripts cycling through a list of API endpoints with the same stolen token. For example:
import requests
def spray_token(token, endpoints):
headers = {'Authorization': f'Bearer {token}'}
results = []
for endpoint in endpoints:
try:
response = requests.get(endpoint, headers=headers, timeout=5)
results.append({
'endpoint': endpoint,
'status_code': response.status_code,
'response_size': len(response.content)
})
except requests.exceptions.RequestException:
results.append({
'endpoint': endpoint,
'status_code': 'timeout',
'response_size': 0
})
return results
# Common admin endpoints attackers target
admin_endpoints = [
'https://api.example.com/admin/users',
'https://api.example.com/admin/config',
'https://api.example.com/admin/logs',
'https://api.example.com/admin/backup'
]
stolen_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
results = spray_token(stolen_token, admin_endpoints)The severity of Bearer token spraying lies in its silent nature. Unlike password-based attacks that trigger account lockouts, token spraying often goes undetected because the token remains valid throughout the attack. Attackers can map entire API surfaces without triggering traditional security mechanisms.
Another variant involves token replay across different services. Many organizations use the same token format across multiple microservices. An attacker who obtains a token valid for one service can systematically test it against others, potentially gaining broader access than intended. This cross-service token spraying is particularly dangerous in microservice architectures where service-to-service authentication relies on shared token validation logic.
Bearer Tokens-Specific Detection
Detecting Bearer token spraying requires monitoring patterns that traditional authentication systems miss. The key is identifying abnormal token usage patterns rather than just failed authentication attempts.
Effective detection starts with token usage analytics. Track the number of unique endpoints accessed per token over time windows. A legitimate user typically accesses a predictable subset of endpoints. When a single token suddenly accesses dozens of unique endpoints across different functional areas, it signals potential spraying activity.
from collections import defaultdict
import time
class TokenUsageMonitor:
def __init__(self):
self.token_activity = defaultdict(list) # token -> [(timestamp, endpoint)]
self.window_seconds = 300 # 5 minute window
def record_access(self, token, endpoint):
now = time.time()
self.token_activity[token].append((now, endpoint))
# Clean old entries
self.token_activity[token] = [
(ts, ep) for ts, ep in self.token_activity[token]
if ts > now - self.window_seconds
]
def detect_spraying(self):
suspicious_tokens = []
for token, accesses in self.token_activity.items():
unique_endpoints = len(set(ep for ts, ep in accesses))
if unique_endpoints > 20: # Threshold: more than 20 unique endpoints
suspicious_tokens.append({
'token': token,
'unique_endpoints': unique_endpoints,
'access_count': len(accesses)
})
return suspicious_tokens
monitor = TokenUsageMonitor()
# During request processing:
# monitor.record_access(incoming_token, request.path)Rate limiting at the token level provides another defense layer. Unlike user-based rate limiting, token-based limits track how many requests a specific token makes regardless of the user identity. This catches scenarios where a single token is being actively sprayed across multiple endpoints.
middleBrick's scanning approach specifically targets Bearer token vulnerabilities through unauthenticated black-box testing. The scanner attempts to identify endpoints that accept tokens without proper scope validation, testing common token formats against administrative paths. middleBrick's LLM security module also checks for AI-specific token spraying patterns in LLM endpoints, where system prompt injection can be achieved through token manipulation.
Network-level detection complements application monitoring. Look for traffic patterns showing a single IP rapidly cycling through API endpoints with consistent Authorization headers. This external view catches spraying attempts before they reach application logic.
Bearer Tokens-Specific Remediation
Remediating Bearer token spraying requires architectural changes to how tokens are issued, validated, and scoped. The goal is to minimize the blast radius of any single token compromise.
Implement token scope limitations at issuance. Rather than issuing monolithic tokens with broad permissions, create scoped tokens that grant access only to specific API groups. This follows the principle of least privilege and contains spraying damage.
from datetime import datetime, timedelta
from jose import jwt
def create_scoped_token(user_id, allowed_endpoints):
# allowed_endpoints: list of endpoint patterns this token can access
payload = {
'user_id': user_id,
'scope': {
'allowed_endpoints': allowed_endpoints,
'issued_at': datetime.utcnow().isoformat()
},
'exp': datetime.utcnow() + timedelta(hours=1),
'iat': datetime.utcnow()
}
token = jwt.encode(payload, 'your-secret-key', algorithm='HS256')
return token
# Issue a token only for specific functionality
admin_token = create_scoped_token(
user_id=123,
allowed_endpoints=['/admin/users/*', '/admin/reports/*']
)
user_token = create_scoped_token(
user_id=123,
allowed_endpoints=['/user/profile', '/user/orders']
)Implement token introspection at each endpoint. Before processing requests, validate that the token is permitted for the specific endpoint being accessed. This prevents tokens from being reused across unintended API surfaces.
from functools import wraps
from jose import jwt
def token_required(allowed_endpoints):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
return {'message': 'Token missing'}, 401
token = auth_header.split(' ')[1]
try:
payload = jwt.decode(token, 'your-secret-key', algorithms=['HS256'])
current_endpoint = request.path
# Check if endpoint is in allowed scopes
if not any(pattern in current_endpoint for pattern in
payload.get('scope', {}).get('allowed_endpoints', [])):
return {'message': 'Token not authorized for this endpoint'}, 403
except jwt.ExpiredSignatureError:
return {'message': 'Token expired'}, 401
except jwt.JWTError:
return {'message': 'Token invalid'}, 401
return f(*args, **kwargs)
return decorated_function
return decorator
@app.route('/admin/users', methods=['GET'])
@token_required(allowed_endpoints=['/admin/users/*'])
def get_users():
# Only tokens with /admin/users/* scope can access
return jsonify(get_all_users())Implement token rotation policies. Short-lived tokens (5-15 minutes) combined with refresh token mechanisms limit the window for successful spraying attacks. Even if an attacker obtains a token, it becomes invalid before comprehensive spraying can occur.
middleBrick's continuous monitoring in Pro tier helps validate these remediation efforts by regularly scanning your APIs for token validation weaknesses. The scanner tests whether tokens can be reused across unintended endpoints and whether scope validation is properly implemented.