{"title":"Template Injection via Flask render_template_string()","language":"Python","severity":"Critical","cwe":"CWE-1336","source_lines":[9,10],"flow_lines":[9,10,11,12],"sink_lines":[12],"vulnerable_code":"from flask import Flask, request, render_template_string\nimport boto3\n\niot_dashboard = Flask(__name__)\ns3_client = boto3.client('s3')\n\n@iot_dashboard.route('/device/status')\ndef fetch_device_metrics():\n    device_id = request.args.get('device_id', 'unknown')\n    metric_type = request.args.get('metric', 'temperature')\n    dashboard_html = f\"<h2>Device: {device_id}</h2><p>Metric: {metric_type}</p><div>{{{{ status_data }}}}</div>\"\n    return render_template_string(dashboard_html, status_data='Active')","explanation":"User-controlled parameters 'device_id' and 'metric' from request.args are directly embedded into an f-string template that is then passed to render_template_string(). This allows attackers to inject arbitrary Jinja2 template expressions that get executed server-side, enabling remote code execution through Server-Side Template Injection (SSTI).","remediation":"The fix removes the f-string interpolation of user-controlled inputs directly into the template string. Instead, it uses a static template with Jinja2 placeholder variables ({{ device_id }}, {{ metric_type }}) and passes user inputs as context parameters to render_template_string(), which automatically escapes them and prevents template injection.","secure_code":"from flask import Flask, request, render_template_string\nimport boto3\nfrom markupsafe import escape\n\niot_dashboard = Flask(__name__)\ns3_client = boto3.client('s3')\n\n@iot_dashboard.route('/device/status')\ndef fetch_device_metrics():\n    device_id = request.args.get('device_id', 'unknown')\n    metric_type = request.args.get('metric', 'temperature')\n    dashboard_html = \"<h2>Device: {{ device_id }}</h2><p>Metric: {{ metric_type }}</p><div>{{ status_data }}</div>\"\n    return render_template_string(dashboard_html, device_id=device_id, metric_type=metric_type, status_data='Active')"}