HIGH server side template injectionapi keys

Server Side Template Injection with Api Keys

How Server Side Template Injection Manifests in API Keys

Server Side Template Injection (SSTI) in API key contexts occurs when user-controlled data is improperly interpolated into templates that generate API key responses, documentation, or configuration files. Unlike traditional SSTI where attackers inject malicious template code, API key SSTI focuses on how template engines handle sensitive credential exposure.

The most common manifestation appears in API documentation endpoints where template engines dynamically generate key examples. Consider a Node.js Express application using Handlebars:

app.get('/api/docs', (req, res) => {
  const apiKey = req.query.demoKey || 'demo-key-123';
  res.render('api-docs', { apiKey });
});

If the template contains:

<pre>Authorization: Bearer {{apiKey}}</pre>

An attacker can manipulate the template context to expose other users' keys through prototype pollution or by accessing global objects. The template engine might resolve {{process.env.API_SECRET}} if not properly sandboxed.

Another pattern emerges in API key generation endpoints where templates construct key strings. Using Jinja2 in Python:

def generate_key(user_id):
    template = Template('API_KEY_{{user_id}}_{{random_string}}')
    return template.render({
        'user_id': user_id,
        'random_string': secrets.token_hex(16)
    })

If user_id contains template syntax like {{config.SECRET}}, the engine may resolve it, exposing configuration secrets in generated keys.

REST API frameworks often use template engines for error responses containing API key information. A Flask endpoint might do:

@app.route('/verify-key')
def verify_key():
    key = request.headers.get('X-API-Key')
    if not key:
        return render_template('error.html', message='Missing API key: {{key}}')
    # verification logic

Here, the error template itself becomes a SSTI vector if it processes the message parameter insecurely.

API key management dashboards frequently use templates to display key metadata. Consider this vulnerable pattern in a Django admin panel:

def key_details(request, key_id):
    key = APIKey.objects.get(id=key_id)
    context = {
        'key': key,
        'metadata': key.metadata_template.format(**key.metadata)
    }
    return render(request, 'key_detail.html', context)

If metadata_template comes from user input and contains template expressions, it creates a SSTI opportunity where attackers can extract other keys through template context manipulation.

SDK generation tools that template API client code also present risks. A tool generating Python SDK code might use:

template = """
class APIClient:
    def __init__(self):
        self.api_key = '{{api_key}}'
"""
client_code = Template(template).render(api_key=generated_key)

If the template engine supports advanced features like filters or macros, attackers might inject code that gets executed during SDK generation.

API Keys-Specific Detection

Detecting SSTI in API key contexts requires examining both template engines and API key handling code. Static analysis tools should flag any template rendering where user input directly populates API key fields without proper sanitization.

Dynamic scanning with middleBrick specifically targets SSTI in API contexts through these mechanisms:

Template Expression Testing - middleBrick injects template syntax payloads like {{7*7}}, {{config}}, and {{[].constructor.constructor('return process.mainModule.require')()}} into API key parameters, headers, and query strings. It monitors responses for template evaluation results rather than literal output.

Context Boundary Testing - The scanner tests whether template contexts expose sensitive objects. It attempts to access process.env, config, request, and application objects through template syntax in API key fields.

Cross-Template Leakage - middleBrick checks if template engines allow cross-referencing between different API key contexts. For example, if one key's template evaluation exposes system information, can that information be accessed through another key's template?

API Documentation Scanning - The tool specifically examines API documentation endpoints that might display key examples. It tests whether these endpoints are vulnerable to template injection that could expose other users' keys or system secrets.

SDK Generation Testing - For platforms that generate client SDKs, middleBrick tests whether template-based code generation can be manipulated to produce malicious client code or expose secrets in the generated output.

Manual detection should focus on these patterns:

grep -r "render(" . | grep -E "(api_key|key|credential)"
grep -r "Template(" . | grep -E "(api_key|key|credential)"

Look for template engines like Handlebars, Jinja2, Mustache, or ERB being used to process API key data. Check if any user input flows into template rendering contexts without proper escaping.

Security headers and CSP policies can help detect template injection attempts. Monitor for unexpected template evaluation in responses that should only contain literal API key strings.

API Keys-Specific Remediation

Remediating SSTI in API key contexts requires both template engine hardening and proper API key handling practices. The most effective approach combines secure coding patterns with runtime protections.

Template Engine Hardening - Configure template engines to disable dangerous features when processing API key data:

# Jinja2: Disable dangerous features
env = Environment(
    loader=FileSystemLoader('templates'),
    autoescape=True,
    optimized=True,
    enable_async=False
)
env.filters.pop('attr', None)  # Remove attribute access
env.globals.pop('__builtins__', None)  # Remove builtins access

Input Validation and Escaping - Never directly interpolate user input into templates that handle API keys:

def safe_key_template(key):
    # Validate key format before templating
    if not re.match(r'^[A-Za-z0-9_-]{20,64}$', key):
        raise ValueError('Invalid API key format')
    
    # Use explicit escaping rather than template interpolation
    return html.escape(key)

Context Isolation - Separate template contexts for API key operations from general application contexts:

class APIKeyTemplateContext:
    def __init__(self):
        self.safe_globals = {'__builtins__': {}}
        self.safe_filters = {'safe': self._safe_filter}
    
    def _safe_filter(self, value):
        # Only allow safe HTML in specific contexts
        if not isinstance(value, str):
            return str(value)
        return mark_safe(escape(value))

API Key Generation Security - Use secure random generation without template interpolation:

import secrets
import base64

def generate_secure_api_key():
    # Generate cryptographically secure key
    random_bytes = secrets.token_bytes(32)
    key = base64.urlsafe_b64encode(random_bytes).decode('utf-8')
    
    # No template processing - return raw key
    return key

Response Sanitization - Ensure API responses containing keys are properly sanitized:

@app.route('/api/keys')
def list_keys():
    keys = APIKey.objects.filter(user=request.user)
    
    # Serialize keys without template processing
    response_data = []
    for key in keys:
        response_data.append({
            'id': key.id,
            'key': mask_key(key.key),  # Never expose full key
            'created_at': key.created_at.isoformat()
        })
    
    return jsonify(response_data)

Template Whitelisting - Implement strict template whitelisting for API key contexts:

SAFE_TEMPLATE_CHARS = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_')

def validate_template_input(value):
    if not isinstance(value, str):
        return False
    
    # Reject any template syntax
    if any(char in value for char in ['{', '}', '%', '#', '@']):
        return False
    
    # Reject suspicious patterns
    if re.search(r'(import|exec|eval|config|process)', value, re.IGNORECASE):
        return False
    
    return True

Runtime Monitoring - Implement monitoring for template injection attempts:

class TemplateInjectionMonitor:
    def __init__(self):
        self.attempt_log = []
        self.suspicious_patterns = [
            r'config', r'process', r'import',
            r'exec', r'eval', r'__builtins__'
        ]
    
    def check_for_injection(self, template_string):
        for pattern in self.suspicious_patterns:
            if re.search(pattern, template_string):
                self.attempt_log.append({
                    'pattern': pattern,
                    'template': template_string,
                    'timestamp': datetime.now()
                })
                return True
        return False

Frequently Asked Questions

How does SSTI in API keys differ from regular SSTI?
SSTI in API keys specifically targets credential exposure through template engines. While regular SSTI focuses on code execution, API key SSTI aims to leak sensitive keys, expose system configuration, or manipulate key generation processes. The attack surface includes API documentation, key management dashboards, and SDK generation tools rather than just web application templates.
Can middleBrick detect SSTI in API key contexts?
Yes, middleBrick's black-box scanning tests API key parameters with template injection payloads to identify SSTI vulnerabilities. It specifically examines API documentation endpoints, key management interfaces, and SDK generation tools for template engine weaknesses that could expose API keys or system secrets.