# Log Forging via Unsanitized User Input in Python logging

Language: Python
Severity: Medium
CWE: CWE-117

## Source
9-10

## Flow
9-10-11

## Sink
11

## Vulnerable Code
```python
import logging
from flask import Flask, request

app = Flask(__name__)
logging.basicConfig(filename='iot_device.log', level=logging.INFO)

@app.route('/device/telemetry', methods=['POST'])
def record_telemetry():
    device_id = request.json.get('device_id', 'unknown')
    sensor_data = request.json.get('sensor_reading', 'N/A')
    logging.info(f'IoT Device {device_id} reported: {sensor_data}')
    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
```python
import logging
import re
from flask import Flask, request

app = Flask(__name__)
logging.basicConfig(filename='iot_device.log', level=logging.INFO)

def sanitize_log_input(value, max_length=256):
    """Sanitize user input for safe logging by removing control characters and limiting length."""
    if not isinstance(value, str):
        value = str(value)
    # Remove newlines, carriage returns, and other control characters
    sanitized = re.sub(r'[\r\n\x00-\x1f\x7f-\x9f]', '', value)
    # Truncate to prevent log flooding
    return sanitized[:max_length]

@app.route('/device/telemetry', methods=['POST'])
def record_telemetry():
    device_id = request.json.get('device_id', 'unknown')
    sensor_data = request.json.get('sensor_reading', 'N/A')
    safe_device_id = sanitize_log_input(device_id)
    safe_sensor_data = sanitize_log_input(sensor_data)
    logging.info(f'IoT Device {safe_device_id} reported: {safe_sensor_data}')
    return {'status': 'telemetry_logged'}, 200
```
