{"title":"Server-Side Template Injection (SSTI)","language":"Python","severity":"Critical","cwe":"CWE-94","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"from flask import Flask, request\nfrom jinja2 import Environment\napp = Flask(__name__)\njinja_env = Environment()\n@app.route('/iot/device/status')\ndef fetch_device_status():\n    dev_label = request.args.get('label', 'unknown')\n    tmpl_str = 'Device Report: {{ ' + dev_label + ' }}'\n    compiled_tmpl = jinja_env.from_string(tmpl_str)\n    rendered_output = compiled_tmpl.render(uptime=9999, temp=72.4)\n    return rendered_output","explanation":"The user-supplied 'label' query parameter (dev_label) is directly concatenated into a Jinja2 template string at line 8 without any sanitization or escaping. This template string is then compiled and rendered by jinja_env.from_string() at line 9, allowing an attacker to inject arbitrary Jinja2 template expressions that are evaluated server-side, potentially leading to remote code execution.","remediation":"The fix eliminates the SSTI vulnerability by never concatenating user input into the Jinja2 template string. Instead, the user-supplied label is validated against a whitelist of allowed device field names, and the resolved value is passed into the template context as a data variable. Additionally, the raw Jinja2 Environment is replaced with SandboxedEnvironment as a defense-in-depth measure to restrict template capabilities even if future template logic changes.","secure_code":"from flask import Flask, request\nfrom jinja2 import Environment, SandboxedEnvironment\napp = Flask(__name__)\njinja_env = SandboxedEnvironment()\n\n# Whitelist of allowed device label names\nALLOWED_LABELS = {'uptime', 'temp', 'humidity', 'pressure', 'voltage', 'status'}\n\n@app.route('/iot/device/status')\ndef fetch_device_status():\n    dev_label = request.args.get('label', 'unknown')\n    # Validate that the label is in the allowed set of known device fields\n    if dev_label not in ALLOWED_LABELS:\n        dev_label = 'unknown'\n    # Use the label as a safe variable reference passed via the template context,\n    # never concatenating user input into the template string itself.\n    tmpl_str = 'Device Report: {{ device_label }}'\n    compiled_tmpl = jinja_env.from_string(tmpl_str)\n    device_data = {'uptime': 9999, 'temp': 72.4, 'humidity': 55.0, 'pressure': 1013, 'voltage': 3.3, 'status': 'online'}\n    label_value = device_data.get(dev_label, dev_label)\n    rendered_output = compiled_tmpl.render(device_label=label_value)\n    return rendered_output"}