{"title":"Command Injection via subprocess.shell","language":"Python","severity":"Critical","cwe":"CWE-78","source_lines":[3,4],"flow_lines":[3,4,5],"sink_lines":[5],"vulnerable_code":"import subprocess\n\ndef trigger_iot_device_reboot(device_mac, reboot_delay):\n    device_id = device_mac.replace(':', '')\n    cmd = f\"curl -X POST https://iot-hub.local/api/reboot?mac={device_id}&delay={reboot_delay}\"\n    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)\n    if result.returncode == 0:\n        return {\"status\": \"success\", \"output\": result.stdout}\n    return {\"status\": \"failed\", \"error\": result.stderr}","explanation":"The function accepts user-controlled parameters (device_mac and reboot_delay) that are directly interpolated into a shell command string without sanitization. This command is then executed via subprocess.run with shell=True, allowing attackers to inject arbitrary shell commands through metacharacters in either parameter.","remediation":"The fix eliminates command injection by passing the command as a list of arguments to subprocess.run without shell=True, which prevents shell metacharacter interpretation. Additionally, strict input validation ensures device_mac matches a valid MAC address pattern and reboot_delay is a valid non-negative integer before use.","secure_code":"import subprocess\nimport re\n\ndef trigger_iot_device_reboot(device_mac, reboot_delay):\n    # Validate MAC address format (only hex digits and colons allowed)\n    if not re.match(r'^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$', device_mac):\n        return {\"status\": \"failed\", \"error\": \"Invalid MAC address format\"}\n    \n    # Validate reboot_delay is a positive integer\n    try:\n        delay_value = int(reboot_delay)\n        if delay_value < 0:\n            return {\"status\": \"failed\", \"error\": \"Delay must be a non-negative integer\"}\n    except (ValueError, TypeError):\n        return {\"status\": \"failed\", \"error\": \"Invalid delay value\"}\n    \n    device_id = device_mac.replace(':', '')\n    \n    # Use subprocess with argument list (no shell=True) to prevent command injection\n    result = subprocess.run(\n        [\"curl\", \"-X\", \"POST\", f\"https://iot-hub.local/api/reboot?mac={device_id}&delay={delay_value}\"],\n        capture_output=True,\n        text=True\n    )\n    if result.returncode == 0:\n        return {\"status\": \"success\", \"output\": result.stdout}\n    return {\"status\": \"failed\", \"error\": result.stderr}"}