{"title":"Template Injection via Jinja2 render_template_string()","language":"Python","severity":"Critical","cwe":"CWE-1336","source_lines":[9,12],"flow_lines":[9,13,14,12,16,17],"sink_lines":[14,17],"vulnerable_code":"from flask import Flask, request, render_template_string\nimport boto3\n\napp = Flask(__name__)\ns3_client = boto3.client('s3')\n\n@app.route('/cloud/bucket-report')\ndef generate_bucket_report():\n    bucket_name = request.args.get('bucket', 'default-bucket')\n    report_format = request.args.get('format', 'html')\n    user_title = request.args.get('title', 'S3 Bucket Report')\n    try:\n        response = s3_client.list_objects_v2(Bucket=bucket_name, MaxKeys=5)\n        object_count = response.get('KeyCount', 0)\n        report_template = f\"<html><head><title>{user_title}</title></head><body><h1>{user_title}</h1><p>Bucket: {bucket_name}</p><p>Objects found: {object_count}</p></body></html>\"\n        return render_template_string(report_template)\n    except Exception as e:\n        error_msg = request.args.get('error_template', 'Error accessing bucket')\n        error_page = f\"<html><body><h2>Cloud Storage Error</h2><p>{error_msg}</p><p>Details: {str(e)}</p></body></html>\"\n        return render_template_string(error_page), 500","explanation":"User-controlled input from request.args.get('title') and request.args.get('error_template') is directly interpolated into f-strings and then passed to render_template_string(), which treats them as Jinja2 templates. This allows attackers to inject arbitrary Jinja2 template expressions that execute on the server.","remediation":"The fix replaces direct f-string interpolation of user input into template strings with Jinja2's built-in variable substitution using {{ }} placeholders and passing user data as context parameters to render_template_string(). This ensures all user-controlled values are automatically escaped by Jinja2's autoescaping and are never interpreted as template code.","secure_code":"from flask import Flask, request, render_template_string\nimport boto3\nfrom markupsafe import escape\n\napp = Flask(__name__)\ns3_client = boto3.client('s3')\n\n@app.route('/cloud/bucket-report')\ndef generate_bucket_report():\n    bucket_name = request.args.get('bucket', 'default-bucket')\n    report_format = request.args.get('format', 'html')\n    user_title = request.args.get('title', 'S3 Bucket Report')\n    try:\n        response = s3_client.list_objects_v2(Bucket=bucket_name, MaxKeys=5)\n        object_count = response.get('KeyCount', 0)\n        report_template = \"<html><head><title>{{ title }}</title></head><body><h1>{{ title }}</h1><p>Bucket: {{ bucket }}</p><p>Objects found: {{ count }}</p></body></html>\"\n        return render_template_string(report_template, title=user_title, bucket=bucket_name, count=object_count)\n    except Exception as e:\n        error_msg = request.args.get('error_template', 'Error accessing bucket')\n        error_page = \"<html><body><h2>Cloud Storage Error</h2><p>{{ error_msg }}</p><p>Details: {{ details }}</p></body></html>\"\n        return render_template_string(error_page, error_msg=error_msg, details=str(e)), 500"}