{"title":"Path Traversal via Untrusted File Open Path Joins","language":"Python","severity":"High","cwe":"CWE-22","source_lines":[8,9],"flow_lines":[8,11,12,9,11,12],"sink_lines":[12],"vulnerable_code":"from flask import Flask, request, send_file\nimport os\n\napp = Flask(__name__)\n\n@app.route('/iot/firmware/download')\ndef retrieve_firmware_binary():\n    device_model = request.args.get('model', 'default')\n    fw_version = request.args.get('ver', '1.0')\n    firmware_base = '/var/iot/firmware_repo'\n    binary_path = os.path.join(firmware_base, device_model, fw_version, 'firmware.bin')\n    if os.path.exists(binary_path):\n        return send_file(binary_path, as_attachment=True)\n    return 'Firmware not found', 404","explanation":"The application constructs a file path using user-controlled parameters 'model' and 'ver' without validation, allowing path traversal attacks. An attacker can use directory traversal sequences (../) in these parameters to escape the intended firmware_base directory and access arbitrary files on the server filesystem.","remediation":"The fix applies a two-layer defense: first, it validates that both user-supplied parameters (model and version) contain only safe alphanumeric characters, hyphens, underscores, and dots using a whitelist regex, rejecting any path traversal characters. Second, it resolves the constructed path to its canonical absolute form using os.path.realpath() and verifies the resolved path remains within the intended firmware base directory, preventing any bypass of the input validation.","secure_code":"from flask import Flask, request, send_file\nimport os\nimport re\n\napp = Flask(__name__)\n\n@app.route('/iot/firmware/download')\ndef retrieve_firmware_binary():\n    device_model = request.args.get('model', 'default')\n    fw_version = request.args.get('ver', '1.0')\n    firmware_base = '/var/iot/firmware_repo'\n\n    # Validate that model and version contain only safe characters (alphanumeric, hyphens, underscores, dots)\n    if not re.match(r'^[a-zA-Z0-9._-]+$', device_model):\n        return 'Invalid model parameter', 400\n    if not re.match(r'^[a-zA-Z0-9._-]+$', fw_version):\n        return 'Invalid version parameter', 400\n\n    binary_path = os.path.join(firmware_base, device_model, fw_version, 'firmware.bin')\n\n    # Resolve the absolute path and verify it stays within the firmware base directory\n    resolved_path = os.path.realpath(binary_path)\n    if not resolved_path.startswith(os.path.realpath(firmware_base) + os.sep):\n        return 'Access denied', 403\n\n    if os.path.exists(resolved_path):\n        return send_file(resolved_path, as_attachment=True)\n    return 'Firmware not found', 404"}