Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion vulnerable_path_traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ def read_file():
@app.route('/view')
def view_document():
doc = request.args.get('doc')
path = f"/documents/{doc}"
base_dir = os.path.realpath("/documents/")
path = os.path.realpath(os.path.join(base_dir, doc))
if not path.startswith(base_dir):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Path traversal bypass via startswith check without trailing separator

os.path.realpath("/documents/") strips the trailing slash, yielding base_dir = "/documents". The check path.startswith(base_dir) on line 27 will therefore also match paths in sibling directories whose names share the same prefix (e.g., /documents_secret/). An attacker supplying doc=../documents_secret/passwd would produce path = "/documents_secret/passwd", which passes "/documents_secret/passwd".startswith("/documents")True, bypassing the security check and reading arbitrary files.

The fix is to ensure the resolved path starts with base_dir + os.sep (or equals base_dir exactly).

Suggested change
if not path.startswith(base_dir):
if not (path == base_dir or path.startswith(base_dir + os.sep)):
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path traversal fix bypassed via startswith without trailing separator

High Severity

The startswith check against base_dir is bypassable because os.path.realpath strips the trailing slash, leaving base_dir as "/documents". A sibling directory like "/documents_secret" would pass the path.startswith("/documents") check, allowing access to files outside the intended directory. The check needs to compare against base_dir + os.sep (or also allow path == base_dir) to be a correct path traversal guard.

Fix in Cursor Fix in Web

return 'Access denied', 403

with open(path) as file:
return file.read()
Expand Down
Loading