# Pickle Deserialization via pickle.loads() on Untrusted Network Data

Language: Python
Severity: Critical
CWE: CWE-502

## Source
5-6

## Flow
5-6-7

## Sink
7

## Vulnerable Code
```python
import pickle
import socket

def receive_iot_telemetry(device_socket):
    telemetry_size = int(device_socket.recv(8).decode())
    serialized_metrics = device_socket.recv(telemetry_size)
    sensor_data = pickle.loads(serialized_metrics)
    temperature = sensor_data.get('temp', 0)
    humidity = sensor_data.get('humidity', 0)
    device_id = sensor_data.get('device_id', 'unknown')
    print(f"Device {device_id}: Temp={temperature}C, Humidity={humidity}%")
    return sensor_data
```

## Explanation

The code receives untrusted serialized data from a network socket and directly deserializes it using pickle.loads() without validation. An attacker controlling the IoT device or intercepting network traffic can send a malicious pickle payload that executes arbitrary Python code during deserialization, leading to remote code execution on the gateway.

## Remediation

The fix replaces pickle.loads() with json.loads() to use a safe deserialization format that cannot execute arbitrary code. Additionally, it adds input validation including payload size limits, allowed key whitelisting, and value type checking to ensure only expected telemetry data is processed.

## Secure Code
```python
import json
import socket

ALLOWED_KEYS = {'temp', 'humidity', 'device_id', 'pressure', 'battery', 'timestamp'}
MAX_PAYLOAD_SIZE = 4096

def receive_iot_telemetry(device_socket):
    size_header = device_socket.recv(8).decode().strip()
    if not size_header.isdigit():
        raise ValueError("Invalid size header received")
    telemetry_size = int(size_header)
    if telemetry_size > MAX_PAYLOAD_SIZE:
        raise ValueError(f"Payload size {telemetry_size} exceeds maximum allowed {MAX_PAYLOAD_SIZE}")
    serialized_metrics = device_socket.recv(telemetry_size)
    try:
        sensor_data = json.loads(serialized_metrics)
    except json.JSONDecodeError as e:
        raise ValueError(f"Invalid JSON telemetry data: {e}")
    if not isinstance(sensor_data, dict):
        raise ValueError("Telemetry data must be a JSON object")
    validated_data = {}
    for key, value in sensor_data.items():
        if key not in ALLOWED_KEYS:
            continue
        if not isinstance(value, (str, int, float, bool, type(None))):
            raise ValueError(f"Invalid value type for key '{key}'")
        validated_data[key] = value
    temperature = validated_data.get('temp', 0)
    humidity = validated_data.get('humidity', 0)
    device_id = str(validated_data.get('device_id', 'unknown'))
    print(f"Device {device_id}: Temp={temperature}C, Humidity={humidity}%")
    return validated_data
```
