HIGH server side template injectionflaskhmac signatures

Server Side Template Injection in Flask with Hmac Signatures

Server Side Template Injection in Flask with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Server Side Template Injection (SSTI) in Flask becomes particularly nuanced when HMAC signatures are used to bind data to trusted operations. Flask does not include built-in template injection by itself, but when developers render user-influenced content into templates using unsafe string interpolation or by passing unchecked values into template contexts, SSTI can manifest even when HMAC signatures protect certain endpoints.

HMAC signatures are typically used to ensure integrity and authenticity of data, for example when a client-supplied query parameter or header must be validated before processing. If a developer includes the signature value or related data directly into a rendered template without proper escaping, an attacker can attempt to break out of the expected data context and inject template code. This commonly happens in scenarios where Flask apps use Jinja2 templates and pass user-controlled values into template variables that are later used in control structures, includes, or macro expansions.

For example, consider a Flask route that verifies an HMAC signature from a request query parameter and then embeds the raw signature into the template context:

from flask import Flask, request, render_template_string
import hmac
import hashlib

app = Flask(__name__)
secret = b'super-secret-key'

@app.route('/verify')
def verify():
    sig = request.args.get('signature', '')
    # naive check for demonstration
    if not hmac.compare_digest(sig, hmac.new(secret, b'data', hashlib.sha256).hexdigest()):
        return 'Invalid signature', 403
    return render_template_string('Signature: {{ sig }}', sig=sig)

If render_template_string receives sig as a template variable and the string contains Jinja2 syntax, the template engine will attempt to evaluate it. An attacker could supply a crafted signature such as {{ config.__class__ }} wrapped in a valid HMAC, causing the template to expose sensitive configuration. Because HMAC verification may pass, the developer assumes safety, but the lack of output encoding or strict input validation enables SSTI.

The risk is amplified when the HMAC is used not only for integrity but also for business logic decisions, such as authorizing a feature flag or selecting a template fragment. If the value used in the template is derived from or influenced by the signed payload, and that value is not escaped or sandboxed, injection can lead to arbitrary code execution within the template context, information disclosure, or unintended behavior.

middleBrick scans such endpoints as part of its BOLA/IDOR and Input Validation checks, identifying places where untrusted data reaches templates even after cryptographic verification. The scanner flags missing output escaping, unsafe use of template variables, and over-trusting signed parameters that enable unauthenticated LLM endpoint probing when LLM components are involved.

Hmac Signatures-Specific Remediation in Flask — concrete code fixes

Remediation focuses on strict separation between verified data and template rendering, and never passing raw client-influenced values into Jinja2 contexts. Treat the HMAC as a gatekeeper, not a source of content.

  • Do not embed raw signature values into templates. Instead, use the signature only for verification and pass only safe, derived values.
  • Use strict allowlists for template selection and avoid dynamic template names derived from user input.
  • Always escape or avoid variable interpolation in templates when dealing with structured data.

Secure example where the HMAC is used only for verification and a fixed template is rendered with safe, non-user-derived data:

from flask import Flask, request, render_template
import hmac
import hashlib

app = Flask(__name__)
secret = b'super-secret-key'

@app.route('/verify')
def verify():
    sig = request.args.get('signature', '')
    expected = hmac.new(secret, b'data', hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        return 'Invalid signature', 403
    # safe: using a static template and no user-controlled variables from the signature
    return render_template('result.html', status='verified')

If you must include a token-like value in the UI, encode or truncate it and ensure it is treated as plain text:

import base64

@app.route('/verify')
def verify():
    sig = request.args.get('signature', '')
    expected = hmac.new(secret, b'data', hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        return 'Invalid signature', 403
    # safe display: show a truncated, non-executable representation
    display = base64.b64encode(sig.encode()).decode()[:16]
    return render_template('result.html', token_display=display)

For advanced use cases involving dynamic includes or macros, enforce an allowlist and avoid eval-like constructs:

@app.route('/page')
def page():
    page_name = request.args.get('page', 'home')
    allowed = {'home', 'about', 'contact'}
    if page_name not in allowed:
        return 'Invalid page', 400
    # safe: page_name is restricted to known templates
    return render_template(f'{page_name}.html')

middleBrick’s CLI can validate these patterns by running middlebrick scan <url> against your endpoints, surfacing SSTI risks even when HMAC checks are present. The GitHub Action can enforce a minimum security score before merges, while the MCP Server enables scanning APIs directly from your AI coding assistant to catch unsafe patterns during development.

Frequently Asked Questions

Does using HMAC signatures alone prevent template injection in Flask?
No. HMAC signatures verify integrity and authenticity of data, but they do not prevent template injection. If the signed value is passed into a template context without proper escaping or validation, an attacker can still inject template code. Use HMAC for verification only and avoid embedding raw user-influenced values in templates.
How can I safely display a token derived from an HMAC in a Flask template?
Do not insert the raw HMAC into the template. Instead, verify the HMAC, then derive a safe representation for display—such as a truncated, base64-encoded substring—and pass only that safe value to the template. Treat the template as an output channel, not a computation context.