{"title":"Log Forging via Unsanitized User Input in Python logging","language":"Python","severity":"Medium","cwe":"CWE-117","source_lines":[9,10],"flow_lines":[9,10,11],"sink_lines":[11],"vulnerable_code":"import logging\nfrom flask import Flask, request\n\napp = Flask(__name__)\nlogging.basicConfig(filename='iot_device.log', level=logging.INFO)\n\n@app.route('/device/telemetry', methods=['POST'])\ndef record_telemetry():\n    device_id = request.json.get('device_id', 'unknown')\n    sensor_data = request.json.get('sensor_reading', 'N/A')\n    logging.info(f'IoT Device {device_id} reported: {sensor_data}')\n    return {'status': 'telemetry_logged'}, 200","explanation":"User-controlled input from JSON request fields (device_id and sensor_data) is directly interpolated into a log message without sanitization. An attacker can inject newline characters and craft fake log entries, potentially hiding malicious activity or creating false security events that mislead incident response teams.","remediation":"The fix introduces a sanitize_log_input() function that strips all control characters (including newlines and carriage returns) from user-supplied input before it is passed to the logging call, preventing log forging attacks. Additionally, input is truncated to a maximum length to prevent log flooding or denial-of-service through excessively large payloads.","secure_code":"import logging\nimport re\nfrom flask import Flask, request\n\napp = Flask(__name__)\nlogging.basicConfig(filename='iot_device.log', level=logging.INFO)\n\ndef sanitize_log_input(value, max_length=256):\n    \"\"\"Sanitize user input for safe logging by removing control characters and limiting length.\"\"\"\n    if not isinstance(value, str):\n        value = str(value)\n    # Remove newlines, carriage returns, and other control characters\n    sanitized = re.sub(r'[\\r\\n\\x00-\\x1f\\x7f-\\x9f]', '', value)\n    # Truncate to prevent log flooding\n    return sanitized[:max_length]\n\n@app.route('/device/telemetry', methods=['POST'])\ndef record_telemetry():\n    device_id = request.json.get('device_id', 'unknown')\n    sensor_data = request.json.get('sensor_reading', 'N/A')\n    safe_device_id = sanitize_log_input(device_id)\n    safe_sensor_data = sanitize_log_input(sensor_data)\n    logging.info(f'IoT Device {safe_device_id} reported: {safe_sensor_data}')\n    return {'status': 'telemetry_logged'}, 200"}