# Template Injection via Flask render_template_string()

Language: Python
Severity: Critical
CWE: CWE-1336

## Source
9-10

## Flow
9-10-11-12

## Sink
12

## Vulnerable Code
```python
from flask import Flask, request, render_template_string
import boto3

iot_dashboard = Flask(__name__)
s3_client = boto3.client('s3')

@iot_dashboard.route('/device/status')
def fetch_device_metrics():
    device_id = request.args.get('device_id', 'unknown')
    metric_type = request.args.get('metric', 'temperature')
    dashboard_html = f"<h2>Device: {device_id}</h2><p>Metric: {metric_type}</p><div>{{{{ status_data }}}}</div>"
    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
```python
from flask import Flask, request, render_template_string
import boto3
from markupsafe import escape

iot_dashboard = Flask(__name__)
s3_client = boto3.client('s3')

@iot_dashboard.route('/device/status')
def fetch_device_metrics():
    device_id = request.args.get('device_id', 'unknown')
    metric_type = request.args.get('metric', 'temperature')
    dashboard_html = "<h2>Device: {{ device_id }}</h2><p>Metric: {{ metric_type }}</p><div>{{ status_data }}</div>"
    return render_template_string(dashboard_html, device_id=device_id, metric_type=metric_type, status_data='Active')
```
