{"title":"Command Injection","language":"Python","severity":"Critical","cwe":"CWE-78","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"import subprocess\nfrom flask import Flask, request, jsonify\napp = Flask(__name__)\n@app.route('/api/iot/ping', methods=['POST'])\ndef device_health_check():\n    dev_addr = request.json.get('device_ip')\n    if not dev_addr:\n        return jsonify({'err': 'missing device_ip'}), 400\n    latency_cmd = f'ping -c 3 {dev_addr}'\n    proc_out = subprocess.check_output(latency_cmd, shell=True, stderr=subprocess.STDOUT)\n    return jsonify({'result': proc_out.decode('utf-8')}), 200","explanation":"The user-supplied 'device_ip' value is retrieved from the POST JSON body on line 6 without any sanitization or validation. It is directly interpolated into a shell command string via f-string on line 9, then executed with shell=True on line 10 via subprocess.check_output(), allowing an attacker to inject arbitrary OS commands by appending shell metacharacters (e.g., semicolons, pipes, backticks) to the IP value.","remediation":"The fix eliminates command injection by (1) strictly validating that the supplied device_ip matches an IPv4 or IPv6 address pattern via regex before use, rejecting any input containing shell metacharacters, and (2) passing the command as a list of arguments to subprocess.check_output without shell=True, so the OS never interprets the input through a shell. Together these two layers ensure no attacker-controlled string can reach a shell for interpretation.","secure_code":"import subprocess\nimport re\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\nIPV4_REGEX = re.compile(\n    r'^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$'\n)\nIPV6_REGEX = re.compile(\n    r'^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$'\n)\n\n\ndef is_valid_ip(addr: str) -> bool:\n    \"\"\"Return True only if addr is a well-formed IPv4 or IPv6 address.\"\"\"\n    return bool(IPV4_REGEX.match(addr) or IPV6_REGEX.match(addr))\n\n\n@app.route('/api/iot/ping', methods=['POST'])\ndef device_health_check():\n    dev_addr = request.json.get('device_ip')\n    if not dev_addr:\n        return jsonify({'err': 'missing device_ip'}), 400\n\n    dev_addr = dev_addr.strip()\n    if not is_valid_ip(dev_addr):\n        return jsonify({'err': 'invalid device_ip format'}), 400\n\n    proc_out = subprocess.check_output(\n        ['ping', '-c', '3', dev_addr],\n        stderr=subprocess.STDOUT\n    )\n    return jsonify({'result': proc_out.decode('utf-8')}), 200"}