Nosql Injection in Django with Bearer Tokens
Nosql Injection in Django with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Nosql Injection occurs when user-controlled input is interpreted as part of a NoSQL query without proper validation or parameterization. In Django, this typically arises when using packages that interface with document stores such as MongoDB (e.g., via djongo or direct pymongo usage) or when building custom query logic that embeds HTTP request data into query structures. Bearer Tokens are often used in API authentication, where a token from an Authorization header (e.g., Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...) is passed to identify users. When token handling and NoSQL query construction intersect, the risk of injection arises if the token or data derived from it is concatenated into query strings or used to dynamically build query filters.
Consider a scenario where an endpoint accepts a bearer token and uses a claim (such as sub or a custom profile identifier) to filter database records without sanitization:
from pymongo import MongoClient
from flask import request
client = MongoClient()
db = client.mydb
def get_user_data():
auth = request.headers.get("Authorization")
if auth and auth.startswith("Bearer "):
token = auth.split(" ")[1]
# Dangerous: directly embedding token-derived data into a NoSQL query
user = db.users.find_one({ "token_id": token })
return {"status": "ok", "data": user}
return {"error": "missing token"}, 401
If an attacker supplies a crafted token such as abc' || { $where: "return true" } || 'def (or uses operator injection patterns known from MongoDB injection, e.g., { $ne: null } via user-controlled fields), the query logic can be altered to bypass intended filters or extract unintended documents. Because the token is treated as data but interpreted as code, the NoSQL query executes with broader permissions than intended. This becomes especially dangerous when the token is also used for authorization decisions elsewhere in the application, allowing horizontal or vertical privilege escalation via injected query logic.
Additionally, if the token is stored or logged in a way that mixes it with query construction (for example, building dynamic queries from request parameters that include token claims), injection surfaces expand. In APIs scanned by middleBrick, such patterns are flagged under the Unsafe Consumption and Input Validation checks, with specific findings tied to improper handling of identifiers and data within NoSQL contexts. The scanner also highlights missing parameterization and lack of strict schema validation as contributors to the risk. Because middleBrick performs black-box testing without credentials, it can detect these patterns by observing anomalous responses or timing differences that indicate query manipulation.
Bearer Tokens-Specific Remediation in Django — concrete code fixes
Remediation focuses on strict input validation, avoiding direct concatenation of token-derived values into NoSQL queries, and using parameterized interfaces. In Django, even when using document-oriented backends, treat all external input—including bearer token claims—as untrusted data.
First, avoid parsing and directly using the bearer token in database queries. Instead, validate the token via a robust library (e.g., PyJWT) and extract only verified, expected claims. Then, map those claims to trusted internal identifiers (such as a user ID stored in your relational database) rather than using raw token strings as query keys:
import jwt
from django.http import JsonResponse
from pymongo import MongoClient
from django.conf import settings
client = MongoClient()
db = client.mydb
def get_user_data(request):
auth = request.headers.get("Authorization")
if not auth or not auth.startswith("Bearer "):
return JsonResponse({"error": "missing token"}, status=401)
token = auth.split(" ")[1]
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
# Use a trusted identifier, not the raw token
user_id = payload.get("user_id")
if not user_id:
return JsonResponse({"error": "invalid token claims"}, status=400)
# Safe: parameterize the query using a known field with strict type
user = db.users.find_one({"_id": user_id})
return JsonResponse({"status": "ok", "data": user})
except jwt.ExpiredSignatureError:
return JsonResponse({"error": "token expired"}, status=401)
except jwt.InvalidTokenError:
return JsonResponse({"error": "invalid token"}, status=401)
Second, enforce strict schema validation on data extracted from tokens before using it in queries. If you must store token metadata in your document store, define explicit fields and validate against expected types and lengths. Avoid dynamic query building that interpolates strings or uses eval-like constructs. For example, constructing queries via dictionary literals with hardcoded keys is safe; concatenating token values into JSON-like query syntax is not.
Third, apply principle of least privilege to the database user associated with the Django application. Ensure the connection used for NoSQL operations does not have broader permissions than necessary (e.g., avoid read-write when read-only suffices). While this does not prevent injection, it limits the impact of a successful injection attempt. The middleBrick Pro plan supports continuous monitoring of such configurations, helping to detect deviations from secure baselines across your API inventory.
Finally, leverage the Django framework’s built-in protections where applicable and integrate security checks into your CI/CD pipeline. Using the middleBrick GitHub Action, you can automatically fail builds if scans detect patterns resembling unsanitized use of identifiers or missing input validation in API endpoints. This helps catch regressions early and ensures that bearer token handling remains consistent with secure coding practices.