# Jinja2 Server-Side Template Injection via Untrusted render_template_string()

Language: Python
Severity: Critical
CWE: CWE-1336

## Source
9-10

## Flow
9-10-11

## Sink
11

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

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

@app.route('/cloud/bucket-status')
def check_bucket_health():
    bucket_name = request.args.get('bucket', 'default-bucket')
    status_msg = request.args.get('custom_message', 'Bucket operational')
    template_output = render_template_string(f"<h2>AWS S3 Status for {bucket_name}</h2><p>Status: {status_msg}</p>")
    return template_output
```

## Explanation

User-controlled input from request.args.get() for both 'bucket' and 'custom_message' parameters is directly embedded into an f-string template and passed to render_template_string() without sanitization. This allows attackers to inject Jinja2 template expressions that will be executed server-side, potentially leading to remote code execution.

## Remediation

The fix replaces the dangerous f-string interpolation with Jinja2's native template variable syntax ({{ variable }}), passing user inputs as context variables to render_template_string(). This ensures Jinja2 automatically escapes the user-provided values and treats them as data rather than template code, preventing any injected template expressions from being evaluated.

## Secure Code
```python
from flask import Flask, request, render_template_string
import boto3
from markupsafe import escape

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

@app.route('/cloud/bucket-status')
def check_bucket_health():
    bucket_name = request.args.get('bucket', 'default-bucket')
    status_msg = request.args.get('custom_message', 'Bucket operational')
    template = "<h2>AWS S3 Status for {{ bucket_name }}</h2><p>Status: {{ status_msg }}</p>"
    template_output = render_template_string(template, bucket_name=bucket_name, status_msg=status_msg)
    return template_output
```
