Fix NoSQL Injection in Falcon
NoSQL Injection (NoSQLi) in Falcon/PyMongo stacks occurs when raw user input from 'req.media' or 'req.params' is passed directly into database query filters. Attackers leverage MongoDB query operators like '$gt', '$ne', or '$regex' to bypass authentication, dump collections, or perform blind data exfiltration. If you're passing a dictionary directly from a request into a find() call, you're pwned.
The Vulnerable Pattern
import falcon
from pymongo import MongoClient
client = MongoClient(‘mongodb://localhost:27017/’)
db = client[‘prod_db’]
class LoginResource:
def on_post(self, req, resp):
# VULNERABLE: req.media is passed directly to find_one.
# Attacker sends: {‘username’: ‘admin’, ‘password’: {‘$ne’: ‘wrong’}}
# MongoDB returns the admin user because the password is ‘not equal’ to ‘wrong’.
user_data = req.media
user = db.users.find_one(user_data)
if user:
resp.media = {'status': 'authenticated', 'token': 'secret_session_blob'}
else:
raise falcon.HTTPUnauthorized(description='Invalid credentials')</code></pre>
The Secure Implementation
The vulnerability lies in the dynamic nature of BSON. When PyMongo receives a dictionary as a query parameter, it interprets keys starting with '$' as query operators. The fix is two-fold: 1. Use a Schema Validator (like Marshmallow or Pydantic) to enforce that input fields are strictly strings, which prevents the injection of nested objects/operators. 2. Never pass the raw input object to the driver; explicitly construct your query filter to ensure user input is treated as a literal value, not a command.
import falcon
from pymongo import MongoClient
from marshmallow import Schema, fields, ValidationError
SECURE: Define a strict schema to enforce types
class LoginSchema(Schema):
username = fields.Str(required=True)
password = fields.Str(required=True)
client = MongoClient(‘mongodb://localhost:27017/’)
db = client[‘prod_db’]
class LoginResource:
def on_post(self, req, resp):
try:
# Validate and sanitize: filters out any keys not in the schema (like $ne)
data = LoginSchema().load(req.media)
# Explicitly map fields to prevent operator injection
user = db.users.find_one({
'username': data['username'],
'password': data['password']
})
if user:
resp.media = {'status': 'authenticated'}
else:
resp.status = falcon.HTTP_401
except ValidationError as err:
raise falcon.HTTPBadRequest(description=str(err.messages))</code></pre>
Your Falcon API
might be exposed to NoSQL Injection
74% of Falcon apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.