Server Side Template Injection on Cloudflare
How Server Side Template Injection Manifests in Cloudflare
Server Side Template Injection (SSTI) in Cloudflare contexts typically arises when user-controlled input is passed into server-side templates that are processed by Cloudflare Workers or by origin integrations that rely on template rendering. While Cloudflare Workers run isolated V8 isolates and do not directly expose classic string-based templating, SSTI can manifest in two primary patterns within a Cloudflare deployment:
- Workers that construct responses by injecting request-derived data into embedded JavaScript strings that are later evaluated via
eval,Function, or template literals with uncontrolled expressions. - Origin applications behind Cloudflare (or Cloudflare Load Balancers) that use server-side template engines (e.g., Handlebars, Nunjucks, EJS) and expose user input to template variables without proper escaping, enabling an attacker to break out of the template context and execute arbitrary logic.
In Workers, an insecure pattern might look like using concatenated strings to build dynamic JavaScript that is then eval’d. For example:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event));
});
async function handleRequest(event) {
const user = new URL(event.request.url).searchParams.get('name') || 'world';
// Unsafe: injecting into a template string that is eval’d
const script = `(function() { return "Hello " + ${user}; })()`;
const result = await unsafeEval(script);
return new Response(result);
}
async function unsafeEval(code) {
// Dangerous: eval on dynamic content
return Function(`"use strict"; return (${code})`)();
}
If user is controlled by an attacker, they can inject arbitrary JavaScript such as alert(1) or attempt to access the Worker’s internal bindings. In origin-side templates (e.g., Handlebars), an attacker may supply input like {{> (lookup . "constructor")("constructor")("return process")() }} in environments that do not strictly sandbox helpers, leading to server-side code execution or information disclosure.
Cloudflare-specific code paths where SSTI risks can surface include dynamic route handlers that interpolate parameters into response bodies, and custom plugins that process user input without canonicalization. Because Cloudflare sits as a proxy, misconfigured origin servers or Workers that reflect input into templates become the vector, not Cloudflare itself. Proper input validation and output encoding at the origin or within Workers are essential to mitigate these paths.
Cloudflare-Specific Detection
Detecting SSTI in a Cloudflare environment requires testing both the Worker code paths and the origin templates that sit behind Cloudflare. Since Cloudflare proxies requests, scanning should target the public-facing endpoint while accounting for Cloudflare’s edge behavior. middleBrick performs black-box scans against the URL you provide, exercising the unauthenticated attack surface in about 5–15 seconds. For SSTI, it runs input validation probes that attempt to break template contexts using payloads such as:
- Classic template delimiters (e.g.,
{{7*7}},{%print%}) to detect interpreted templates. - Server-side includes or eval-like patterns designed to trigger code execution in misconfigured server-side renderers.
- Property lookups and constructor traversals common in Node.js template engines to identify broken sandboxing.
When using the CLI, you can scan an endpoint with:
middlebrick scan https://api.example.com/v1/resource
The CLI outputs a JSON report with per-category findings, including severity, evidence, and remediation guidance. In the Web Dashboard, you can track the security score over time and review the SSTI-specific findings under Input Validation and Unsafe Consumption checks. The GitHub Action can enforce a minimum score threshold in CI/CD, preventing deployments that introduce new SSTI risks. For LLM-specific endpoints (if your API exposes generative features), middleBrick’s LLM Security checks also probe for prompt injection and output leakage that could compound template-related issues.
Cloudflare-Specific Remediation
Remediation centers on preventing user input from being interpreted as code or template logic. In Cloudflare Workers, avoid eval, Function, or dynamic template literals that incorporate unchecked data. Instead, use strict string building and sanitize inputs with canonicalization. For example:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event));
});
async function handleRequest(event) {
const raw = new URL(event.request.url).searchParams.get('name');
const name = typeof raw === 'string' ? raw.replace(/[^a-zA-Z0-9_\- ]/g, '') : 'world';
const response = `Hello ${name}`;
return new Response(response);
}
This approach ensures that only alphanumeric characters, underscores, hyphens, and spaces are allowed, effectively neutralizing injection attempts.
For origin applications using server-side template engines, apply context-aware escaping provided by the engine. In Handlebars, use triple-stash {{{ }}} only when you trust the input; otherwise prefer double-stash {{ }} which escapes HTML. For Nunjucks, use {{ value | safe }} sparingly and only after validation. A safer pattern is to treat templates as static where possible and pass data through a strict schema:
const schema = {
type: 'object',
properties: {
name: { type: 'string', pattern: '^[A-Za-z0-9 _-]{1,100}$' }
},
required: ['name']
};
function renderTemplate(data) {
const validated = validate(schema, data);
// Use a sandboxed renderer that does not allow arbitrary code
return engine.render('template.html', { name: validated.name });
}
Additionally, place Cloudflare in front of vulnerable origins with WAF rules that block known template injection patterns as a temporary mitigation, while you remediate the underlying templates. Combine this with continuous scanning in CI/CD using the middleBrick GitHub Action to ensure that future changes do not reintroduce SSTI risks.