{"title":"Template Injection via str.format_map()","language":"Python","severity":"Critical","cwe":"CWE-1336","source_lines":[1],"flow_lines":[1,7,8],"sink_lines":[8],"vulnerable_code":"def provision_iot_device(device_id, user_params):\n    device_template = \"Device {device_id} provisioned with firmware={fw_version} and endpoint={endpoint}\"\n    default_config = {\n        'device_id': device_id,\n        'fw_version': '2.1.4',\n        'endpoint': 'iot.cloud.example.com'\n    }\n    merged_config = {**default_config, **user_params}\n    provisioning_log = device_template.format_map(merged_config)\n    return provisioning_log","explanation":"The function accepts untrusted user_params that are merged into merged_config and then passed to format_map(). Python's format_map() allows access to object attributes and methods, enabling attackers to inject format strings that access sensitive globals, execute arbitrary code via __init__.__globals__, or leak information.","remediation":"The fix applies three layers of defense: (1) a whitelist of allowed parameter keys prevents injection of dangerous keys like '__init__', (2) input validation rejects values containing curly braces that could be used for nested format string attacks, and (3) f-string interpolation with explicit dictionary key access replaces format_map() to eliminate the attribute traversal attack surface entirely.","secure_code":"def provision_iot_device(device_id, user_params):\n    ALLOWED_PARAMS = {'fw_version', 'endpoint'}\n    \n    default_config = {\n        'fw_version': '2.1.4',\n        'endpoint': 'iot.cloud.example.com'\n    }\n    \n    # Only allow whitelisted keys from user_params with sanitized string values\n    sanitized_params = {}\n    for key, value in user_params.items():\n        if key in ALLOWED_PARAMS:\n            # Ensure value is a plain string and does not contain format specifiers\n            sanitized_value = str(value)\n            if '{' in sanitized_value or '}' in sanitized_value:\n                raise ValueError(f\"Invalid characters in parameter '{key}': curly braces are not allowed\")\n            sanitized_params[key] = sanitized_value\n    \n    merged_config = {**default_config, **sanitized_params}\n    \n    # Use safe string concatenation instead of format_map to avoid attribute access\n    provisioning_log = (\n        f\"Device {device_id} provisioned with \"\n        f\"firmware={merged_config['fw_version']} and \"\n        f\"endpoint={merged_config['endpoint']}\"\n    )\n    return provisioning_log"}