{"title":"Path Traversal via unvalidated pathlib.Path.joinpath()","language":"Python","severity":"Critical","cwe":"CWE-22","source_lines":[9],"flow_lines":[9,10],"sink_lines":[10],"vulnerable_code":"from pathlib import Path\nfrom flask import Flask, request, send_file\n\napp = Flask(__name__)\nHSM_KEY_VAULT = Path(\"/secure/hsm/keystore\")\n\n@app.route(\"/api/hsm/export-key\")\ndef export_cryptographic_key():\n    key_identifier = request.args.get(\"key_id\", \"default\")\n    key_file_path = HSM_KEY_VAULT.joinpath(key_identifier)\n    if key_file_path.exists():\n        return send_file(key_file_path, as_attachment=True)\n    return {\"error\": \"Key not found\"}, 404","explanation":"The application accepts a user-controlled 'key_id' parameter and directly passes it to pathlib.Path.joinpath() without validation. An attacker can use path traversal sequences (e.g., '../../../etc/passwd') to escape the intended HSM_KEY_VAULT directory and access arbitrary files on the filesystem, which are then served via send_file().","remediation":"The fix resolves the constructed path to its absolute canonical form using .resolve(), then validates that the resolved path is still within the intended HSM_KEY_VAULT directory using .is_relative_to(). This prevents path traversal attacks because any '../' sequences are resolved before the containment check, ensuring the final path cannot escape the designated keystore directory.","secure_code":"from pathlib import Path\nfrom flask import Flask, request, send_file\n\napp = Flask(__name__)\nHSM_KEY_VAULT = Path(\"/secure/hsm/keystore\")\n\n@app.route(\"/api/hsm/export-key\")\ndef export_cryptographic_key():\n    key_identifier = request.args.get(\"key_id\", \"default\")\n    key_file_path = HSM_KEY_VAULT.joinpath(key_identifier).resolve()\n    if not key_file_path.is_relative_to(HSM_KEY_VAULT.resolve()):\n        return {\"error\": \"Invalid key identifier\"}, 400\n    if key_file_path.exists():\n        return send_file(key_file_path, as_attachment=True)\n    return {\"error\": \"Key not found\"}, 404"}