Xss Cross Site Scripting in Django with Bearer Tokens
Xss Cross Site Scripting in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Cross-site scripting (XSS) in Django when Bearer Tokens are used centers on how tokens are handled in requests and how responses are rendered. When an API endpoint accepts a Bearer Token via the Authorization header and also reflects data from user-controlled sources into HTML or JavaScript without proper escaping, an attacker can inject malicious scripts. For example, if a Django view reads token-related metadata (such as scopes or client names) from the token payload and embeds that data directly into a template using {{ value }} without escaping, and the token is obtained from an untrusted source or logged in an unsafe manner, the stage is set for stored or reflected XSS.
Django’s built-in template escaping protects against many XSS vectors, but it does not automatically sanitize values that are marked as safe or that are injected via JavaScript. If a Bearer Token is used to personalize content (e.g., “Welcome, {username_from_token}”) and that content is rendered in a script context or as HTML without additional escaping, an attacker who can influence the token payload (via social engineering or a compromised issuer) may inject script code. In SPAs or API-driven frontends, Bearer Tokens are often stored in JavaScript-accessible storage (localStorage/sessionStorage), and if the application embeds token-derived data into the DOM using innerHTML or inserts JSON directly into templates without proper encoding, reflected XSS becomes feasible.
Another vector involves logging or error messages that include Bearer Token fragments. If an exception handler inadvertently includes the token or associated user data in an HTML response, and that response is viewed in a browser, injected script can execute in the context of the victim’s session. Django’s debug pages may expose such data during development, but even in production, custom error handlers that include raw request data can lead to XSS when tokens or user-supplied data are not sanitized.
It is important to note that the presence of Bearer Tokens does not inherently cause XSS; rather, the risk arises when token-derived data is placed into HTML, JavaScript, or CSS without appropriate encoding or validation. The OWASP API Top 10 highlights injection flaws and insufficient output encoding as prominent concerns, and XSS remains a critical risk when APIs serve content to browsers or when API responses are consumed by client-side frameworks that dynamically render data.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
To mitigate XSS risks when using Bearer Tokens in Django, focus on strict separation between data and rendering, proper escaping, and avoiding direct embedding of token-derived values into HTML or JavaScript. Follow these concrete practices with code examples.
1. Use Django’s autoescape and safe filters deliberately
Ensure template variables are escaped unless you explicitly trust the content. Do not mark token-derived data as safe.
{% autoescape on %}
<div>Welcome, {{ username }}</div>
{% endautoescape %}
Avoid using the |safe filter on any data derived from tokens or user input.
2. Encode data when inserting into JavaScript
When passing data from Django views to JavaScript, use JSON serialization and HTML-escape the output to prevent script injection.
<script>
var userData = {{ user_data_json|escapejs }};
</script>
Better yet, place JSON in a <script> tag with type="application/json" and read it via DOM APIs.
<script type="application/json" id="user-data">{{ user_data_json }}</script>
<script>
var raw = document.getElementById('user-data').textContent;
var userData = JSON.parse(raw);
</script>
3. Validate and sanitize token payload claims before use
If your view extracts claims from a Bearer Token (e.g., using a library like PyJWT), validate and sanitize those claims before any output.
import jwt
from django.utils.html import escape
def my_view(request):
auth = request.headers.get('Authorization')
if auth and auth.startswith('Bearer '):
token = auth.split(' ')[1]
try:
payload = jwt.decode(token, options={"verify_signature": False})
username = escape(str(payload.get('username', '')))
# Use username safely in context
return render(request, 'template.html', {'username': username})
except jwt.PyJWTError:
pass
4. Avoid logging or exposing tokens in responses
Ensure that token values or sensitive claims are never included in logs that may be rendered in error pages or responses. Configure logging filters to redact authorization headers.
import logging
logger = logging.getLogger(__name__)
class RedactAuthFilter(logging.Filter):
def filter(self, record):
if hasattr(record, 'msg'):
record.msg = str(record.msg).replace('Bearer ', 'Bearer [redacted]')
return True
logger.addFilter(RedactAuthFilter())
5. Use Django middleware to enforce secure headers and CSP
While not directly token-specific, a strong Content Security Policy reduces the impact of any potential XSS.
# settings.py
MIDDLEWARE = [
...
'django.middleware.security.SecurityMiddleware',
]
SECURE_CROSS_ORIGIN_OPENER_POLICY = 'same-origin'
SECURE_CROSS_ORIGIN_EMBEDDER_POLICY = 'require-corp'
6. API responses that serve HTML must treat Bearer context carefully
If your Django endpoint returns HTML that includes data derived from Bearer Tokens, apply output encoding consistently and prefer JSON-based APIs with strict Content-Type headers to reduce mixed-context risks.
from django.http import JsonResponse
def api_user_info(request):
auth = request.headers.get('Authorization')
# process token and build response
return JsonResponse({'username': safe_username}, json_dumps_params={'ensure_ascii': False})
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 |