from mako.template import Template
from flask import Flask, request
@app.route('/render_template')
def render_template():
# Vulnerable: User input directly in Mako template
user_input = request.args.get('content', '')
# Dangerous: Mako can execute arbitrary Python code
template_str = f'Hello, {user_input}!'
template = Template(template_str)
return template.render()
@app.route('/custom_page')
def custom_page():
# Vulnerable: User-controlled template content
page_content = request.form.get('content')
# Extremely dangerous: Full template control to user
template = Template(page_content)
return template.render(user='admin', role='user')
@app.route('/dynamic_template')
def dynamic_template():
# Vulnerable: Code execution via template variables
data = request.get_json()
template_str = '''<%
result = eval(data['expression'])
%>
Result: ${result}'''
template = Template(template_str)
return template.render(data=data)
from mako.template import Template
from mako.lookup import TemplateLookup
from mako import exceptions
from flask import Flask, request
import re
import html
# Secure template configuration
class SecureTemplateLookup(TemplateLookup):
"""Secure template lookup with restrictions."""
def __init__(self, *args, **kwargs):
# Disable code execution features
kwargs['default_filters'] = ['h'] # HTML escape by default
kwargs['strict_undefined'] = True
super().__init__(*args, **kwargs)
# Safe template rendering function
def safe_render_template(template_string, variables=None, max_length=1000):
"""Safely render template with validation."""
if len(template_string) > max_length:
raise ValueError('Template too long')
# Check for dangerous patterns
dangerous_patterns = [
r'<%.*%>', # Code blocks
r'eval\(',
r'exec\(',
r'import\s+',
r'__.*__', # Dunder methods
r'\${.*\(.*\)}', # Function calls in expressions
]
for pattern in dangerous_patterns:
if re.search(pattern, template_string, re.IGNORECASE):
raise ValueError(f'Dangerous template pattern detected: {pattern}')
# Sanitize variables
safe_variables = {}
if variables:
for key, value in variables.items():
if isinstance(key, str) and key.isalnum():
if isinstance(value, (str, int, float, bool)):
safe_variables[key] = value
try:
# Create template with restrictions
template = Template(
template_string,
default_filters=['h'], # HTML escape
strict_undefined=True
)
return template.render(**safe_variables)
except exceptions.MakoException as e:
raise ValueError(f'Template rendering failed: {str(e)}')
@app.route('/render_template')
def render_template():
"""Secure template rendering with validation."""
user_input = request.args.get('content', '')
# Validate and sanitize input
if not user_input:
return 'No content provided', 400
# Only allow alphanumeric and basic punctuation
if not re.match(r'^[a-zA-Z0-9\s.,!?\-_]+$', user_input):
return 'Invalid characters in content', 400
# Limit length
if len(user_input) > 100:
return 'Content too long', 400
try:
# Safe template with escaped content
template_str = 'Hello, ${content | h}!' # |h forces HTML escaping
result = safe_render_template(
template_str,
{'content': user_input}
)
return result
except ValueError as e:
return f'Template error: {str(e)}', 400
@app.route('/custom_page')
def custom_page():
"""Secure custom page with predefined templates."""
# Don't allow user-controlled templates
return 'Custom templates disabled for security', 403
# Alternative: Use predefined safe templates
SAFE_TEMPLATES = {
'welcome': 'Welcome, ${username | h}!',
'profile': 'User: ${username | h}, Role: ${role | h}',
'message': 'Message: ${text | h}'
}
@app.route('/safe_template/')
def safe_template(template_name):
"""Render predefined safe templates only."""
if template_name not in SAFE_TEMPLATES:
return 'Template not found', 404
# Get template variables from query parameters
variables = {}
for key in ['username', 'role', 'text']:
value = request.args.get(key, '')
if value and len(value) <= 50 and value.replace(' ', '').isalnum():
variables[key] = value
try:
template_str = SAFE_TEMPLATES[template_name]
result = safe_render_template(template_str, variables)
return result
except ValueError as e:
return f'Template error: {str(e)}', 400
# Secure alternative: Use Jinja2 instead
@app.route('/jinja_alternative')
def jinja_alternative():
"""Secure alternative using Jinja2."""
from jinja2 import Environment, select_autoescape
# Secure Jinja2 environment
env = Environment(
autoescape=select_autoescape(['html', 'xml']),
trim_blocks=True,
lstrip_blocks=True
)
user_input = request.args.get('content', '')
# Validate input
if not re.match(r'^[a-zA-Z0-9\s.,!?\-_]+$', user_input):
return 'Invalid input', 400
# Safe template rendering with Jinja2
template = env.from_string('Hello, {{ content }}!')
return template.render(content=user_input)
# Template security checker
def check_template_security(template_content):
"""Check template for security issues."""
issues = []
# Check for code execution patterns
if '<%' in template_content and '%>' in template_content:
issues.append('Code blocks detected')
if re.search(r'eval|exec|import|__.*__', template_content):
issues.append('Dangerous function calls detected')
if '${' in template_content and '(' in template_content:
issues.append('Function calls in expressions detected')
return issues
@app.route('/validate_template', methods=['POST'])
def validate_template():
"""Validate template for security issues."""
template_content = request.form.get('template', '')
if not template_content:
return {'error': 'No template provided'}, 400
issues = check_template_security(template_content)
if issues:
return {
'valid': False,
'issues': issues
}, 400
return {
'valid': True,
'message': 'Template appears safe'
}