Command Injection in Django with Bearer Tokens
Command Injection in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Command Injection occurs when untrusted input is passed to a system shell or command processor without proper validation or escaping. In Django, this risk can intersect with Bearer Token usage when token-driven workflows (e.g., API route protection or service-to-service calls) involve dynamic command construction. For example, if a Django view accepts a token value from an HTTP Authorization header and uses it to invoke a subprocess—such as calling an external tool with the token as an argument—unsanitized input may enable shell metacharacters to alter command behavior.
Consider a scenario where a Django service uses a Bearer Token to authenticate against a third‑party API and then passes the token to a shell command for logging or transformation. If the token is concatenated directly into a command string and executed via subprocess without validation, an attacker who can influence the token (for instance, through a compromised client or a misconfigured endpoint) may inject shell commands. A malicious token like abc123; cat /etc/passwd could cause the system to execute arbitrary commands, leading to data exfiltration or server compromise.
Even when Bearer Tokens are used strictly for authentication headers, improper handling in logging, monitoring, or external tooling can expose them in command-line arguments. Commands such as curl -H "Authorization: Bearer TOKEN" may appear safe, but if the token is derived from user-controlled data and passed through unsafe string building, the attack surface expands. This is especially relevant when token values contain characters that are interpreted by the shell, such as spaces, semicolons, or backticks.
The combination of Django’s web layer and external command execution amplifies the impact. An attacker who can influence a Bearer Token might not directly exploit Command Injection, but if the token reaches a vulnerable subprocess, the boundary between authentication and execution blurs. This illustrates why tokens must be treated as untrusted input when they traverse into system-level operations, and why secure coding practices are essential even for seemingly trusted credentials.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
To mitigate Command Injection risks when working with Bearer Tokens in Django, avoid passing token values directly to shell commands. Instead, use safe abstractions and strict input validation. Below are concrete, secure patterns.
- Validate and sanitize token sources: Treat any token from headers, query parameters, or request bodies as untrusted. Use Django’s form and field validation to enforce expected formats (e.g., alphanumeric with limited length).
- Use subprocess with argument lists: When external commands are necessary, pass arguments as a list to avoid shell interpretation. Never build command strings via concatenation.
import subprocess
from django.http import JsonResponse
from django.views import View
import re
class SafeTokenCommandView(View):
def post(self, request):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not re.match(r'^[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+\.?[A-Za-z0-9\-_.+/=]*$', token):
return JsonResponse({'error': 'Invalid token format'}, status=400)
# Safe execution using a list to avoid shell injection
try:
result = subprocess.run(
['your-command', '--token', token],
capture_output=True,
text=True,
timeout=10
)
return JsonResponse({'stdout': result.stdout})
except subprocess.CalledProcessError as e:
return JsonResponse({'error': str(e)}, status=500)
except Exception as e:
return JsonResponse({'error': 'Server error'}, status=500)
- Avoid shell=True: When using
subprocess, setshell=False(the default) to prevent the shell from interpreting metacharacters. If you must useshell=Truefor complex commands, rigorously escape all inputs, but prefer list-based invocation. - Secure logging and monitoring: Ensure logs that include tokens redact or omit the full value. Use structured logging with token masking to prevent accidental exposure in log files that might be accessed by external tools.
import logging
logger = logging.getLogger(__name__)
def log_token_event(token):
masked = token[:4] + '...' + token[-4:] if len(token) > 8 else '****'
logger.info('Token used for external call', extra={'masked_token': masked})
- Leverage Django security middleware and CSP: While not directly preventing Command Injection, these measures reduce the impact of compromised tokens and complement input validation.
- For API interactions, prefer Django’s HTTP clients: Use
requestsorhttpxwith explicit headers instead of shell commands. This keeps token handling within Python’s safe runtime and avoids shell injection vectors entirely.
import requests
from django.http import JsonResponse
from django.views import View
class RequestsBasedView(View):
def get(self, request):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
try:
response = requests.get(
'https://api.example.com/data',
headers={'Authorization': f'Bearer {token}'}
)
response.raise_for_status()
return JsonResponse(response.json())
except requests.RequestException:
return JsonResponse({'error': 'Service unavailable'}, status=503)
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 |