Path Traversal in Flask with Mongodb
Path Traversal in Flask with Mongodb — how this specific combination creates or exposes the vulnerability
Path Traversal occurs when an attacker manipulates a file path input to access files outside the intended directory. In a Flask application using Mongodb, the risk typically arises not from Mongodb itself, but from how file paths are handled before interacting with the database or filesystem. For example, a Flask route that accepts a filename parameter to retrieve user documents might directly concatenate user input into a filesystem path or store/retrieve file references in Mongodb without strict validation.
Consider a scenario where a Flask endpoint accepts a file_id query parameter, queries Mongodb for a document containing a stored file path, and then uses that path to serve the file. If the stored path in Mongodb reflects unsanitized user input (e.g., a filename provided during upload), and the Flask code uses that path in operations like open() or send_file(), an attacker could supply crafted input such as ../../../etc/passwd to traverse directories. Even though Mongodb only stores the manipulated path, the vulnerability is realized at the filesystem interaction layer. The combination is risky because Mongodb may return a path that appears valid in the database but leads to unauthorized file access when used by Flask.
Another exposure pattern involves storing user-controlled filenames directly in Mongodb without normalization or restriction. If an upload route saves the original filename into a Mongodb document and later uses that filename to construct filesystem paths without checking directory boundaries, an attacker can upload a file with a malicious name and later trigger path traversal through the stored reference. The unauthenticated scan capability of middleBrick can detect such exposed endpoints by analyzing the API surface and identifying routes that accept file or path parameters without proper access controls, highlighting where user input reaches filesystem operations.
In this stack, the OWASP API Top 10 category for Path Traversal intersects with common misconfigurations in how application logic mediates between Mongodb records and filesystem resources. Unlike some environments, Flask does not inherently sanitize paths, so developers must explicitly validate and restrict file locations. middleBrick’s checks for BFLA/Privilege Escalation and Property Authorization can help identify whether endpoints incorrectly expose file access logic based on insufficient ownership checks, which is especially relevant when file paths are derived from Mongodb data.
Mongodb-Specific Remediation in Flask — concrete code fixes
To secure the Flask and Mongodb combination, always treat filenames and paths as untrusted. Validate and sanitize all user input that influences file system paths, and avoid directly using database-stored paths for filesystem operations without additional checks.
Safe file retrieval with path validation
Instead of trusting a path stored in Mongodb, resolve file access through a controlled mapping. Use a unique identifier to locate the file record in Mongodb, then derive the filesystem path server-side from a trusted base directory.
from flask import Flask, send_file, abort
from pymongo import MongoClient
import os
app = Flask(__name__)
client = MongoClient("mongodb://localhost:27017")
db = client["secure_files"]
files_collection = db["files"]
BASE_DIR = "/safe/upload/directory"
@app.route("/download")
def download_file():
file_id = request.args.get("id")
if not file_id:
abort(400, "Missing file identifier")
# Retrieve document by _id or another trusted key
file_record = files_collection.find_one({"_id": ObjectId(file_id)})
if not file_record:
abort(404, "File not found")
# Use a server-side filename, not user-supplied path
safe_filename = file_record["safe_name"]
file_path = os.path.join(BASE_DIR, safe_filename)
if not os.path.commonpath([os.path.realpath(file_path), os.path.realpath(BASE_DIR)]) == os.path.realpath(BASE_DIR):
abort(403, "Invalid path")
return send_file(file_path, as_attachment=True, download_name=safe_filename)
Secure file upload with normalized naming
When storing files, generate a safe filename on the server and store only this normalized name in Mongodb. Do not rely on the original filename provided by the user.
import uuid
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = "/safe/upload/directory"
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
def save_file_stream(file_stream, original_filename):
# Generate a secure, unique filename
ext = os.path.splitext(secure_filename(original_filename))[1]
safe_name = f"{uuid.uuid4().hex}{ext}"
file_path = os.path.join(UPLOAD_FOLDER, safe_name)
with open(file_path, "wb") as f:
for chunk in file_stream:
f.write(chunk)
# Store only the safe name and metadata in Mongodb
files_collection.insert_one({
"original_name": original_filename,
"safe_name": safe_name,
"path": file_path
})
return safe_name
Input validation and framework tools
Use strict allowlists for file extensions and validate filenames with secure_filename from Werkzeug. Avoid passing user input directly to filesystem APIs. In Flask, prefer built-in utilities for path handling and always use absolute paths resolved against a known base directory.
middleBrick’s CLI can be used to scan endpoints handling file parameters, and the Pro plan’s continuous monitoring can help detect regressions where path handling might become unsafe after code changes.
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 |