{"title":"Pickle Deserialization via __reduce__","language":"Python","severity":"Critical","cwe":"CWE-502","source_lines":[10],"flow_lines":[10,11,12],"sink_lines":[12],"vulnerable_code":"import pickle\nimport base64\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/restore', methods=['POST'])\ndef restore_device_config():\n    encoded_state = request.json.get('device_state')\n    if encoded_state:\n        serialized_data = base64.b64decode(encoded_state)\n        device_config = pickle.loads(serialized_data)\n        return jsonify({'status': 'restored', 'config': str(device_config)})\n    return jsonify({'error': 'no state provided'}), 400","explanation":"The application accepts a base64-encoded serialized object from user input via request.json.get('device_state'), decodes it, and directly deserializes it using pickle.loads() without validation. Pickle deserialization of untrusted data allows arbitrary code execution through specially crafted __reduce__ methods in malicious objects.","remediation":"The fix replaces pickle deserialization with JSON deserialization, which does not allow arbitrary code execution since JSON only supports basic data types (strings, numbers, booleans, arrays, objects, null). Additionally, a JSON schema validation step is added to ensure the deserialized configuration conforms to an expected structure, providing defense-in-depth against malformed input.","secure_code":"import json\nimport base64\nfrom flask import Flask, request, jsonify\nfrom jsonschema import validate, ValidationError\n\napp = Flask(__name__)\n\n# Define expected schema for device configuration\nDEVICE_CONFIG_SCHEMA = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"device_id\": {\"type\": \"string\"},\n        \"firmware_version\": {\"type\": \"string\"},\n        \"settings\": {\"type\": \"object\"},\n        \"network\": {\"type\": \"object\"},\n        \"sensors\": {\"type\": \"array\"}\n    },\n    \"required\": [\"device_id\"],\n    \"additionalProperties\": false\n}\n\n@app.route('/iot/device/restore', methods=['POST'])\ndef restore_device_config():\n    encoded_state = request.json.get('device_state')\n    if encoded_state:\n        try:\n            serialized_data = base64.b64decode(encoded_state)\n            device_config = json.loads(serialized_data)\n            validate(instance=device_config, schema=DEVICE_CONFIG_SCHEMA)\n            return jsonify({'status': 'restored', 'config': device_config})\n        except (ValueError, json.JSONDecodeError) as e:\n            return jsonify({'error': 'invalid state data format'}), 400\n        except ValidationError as e:\n            return jsonify({'error': 'invalid device configuration schema'}), 400\n    return jsonify({'error': 'no state provided'}), 400"}