Join our Newsletter — 33% off our NHI Course
Home› Guides› Server-Side Template Injection (SSTI) Guide: Detection and Prevention
Guide Web & API Security

Server-Side Template Injection (SSTI) Guide: Detection and Prevention

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 12 min read
On this page

Server-side template injection (SSTI) happens when user input becomes part of a template instead of data passed into it, so the template engine evaluates that input as expressions or code on the server. Modern engines are expressive enough that this often leads to remote code execution, and SSTI has produced critical, actively exploited flaws such as CVE-2023-22527 in Atlassian Confluence. The risk is growing as more products let users customise emails, documents, notifications and AI prompts with template syntax. This guide explains how SSTI arises, where it hides, how to detect it and how to prevent it, for developers, AppSec engineers, detection teams and the leaders who decide whether users may edit templates at all. It contains no payloads. For the wider family of web attacks, see the Web Application Attacks Guide.

Key takeaways

  • Templates are code. Pass user input into a fixed template as data; never build the template string from input. Treat any feature that lets users author templates as letting them write code.
  • Prefer less powerful engines. Logic-less engines reduce what injected syntax can do. Choose the least expressive engine that meets the requirement.
  • Sandboxes reduce risk, they do not remove it. Jinja's own documentation says the sandbox alone is not a solution for perfect security, and PortSwigger notes sandboxes are prone to bypasses. Add isolation around them.
  • Limit what the template can reach. Expose only plain data to templates, never objects with methods that touch files, the network, class loading or credentials.
  • Detect the outcome, not the syntax. Template syntax is legitimate in many apps; a rendering process spawning shells or reading secrets is not.

How the attack works

MITRE classifies SSTI as CWE-1336, Improper Neutralization of Special Elements Used in a Template Engine, a Base weakness and a child of CWE-94 Code Injection, with CWE-917 Expression Language Injection as a peer. CWE names Twig, Jinja2, Pug, JavaServer Pages, FreeMarker, Velocity, ColdFusion and Smarty as engines involved, and notes that both server-side and client-side engines are affected. CAPEC covers the pattern under CAPEC-242 Code Injection. See the CWE Top 25 Guide.

Template engines combine a fixed template with a data context. Used safely, user input only ever appears in the context and is rendered as text. PortSwigger describes the root cause as user input being concatenated into the template rather than passed in as data. Typical routes:

  • Dynamic template construction: code builds a template string with string formatting (a greeting, a subject line, an error message) and then renders it.
  • User-authored templates: the product deliberately lets administrators, tenants or content editors write templates for emails, invoices, reports or pages. If any such account is compromised or under-trusted, the template engine becomes an execution surface.
  • Stored input rendered later: a value saved in one feature (a profile field, a ticket title, a product description) is later fed into template compilation by another feature, often a background job.
  • Expression language evaluation: frameworks that evaluate OGNL, SpEL or Java EL on request data behave the same way; Confluence CVE-2023-22527 was an OGNL template injection.

From there the attacker uses the engine's features (attribute access, method calls, object introspection, built-in functions) to reach objects that read files, run commands or load classes. How far they get depends on the engine and on what objects are in scope.

SSTI and its relatives

ClassWhere evaluation happensTypical impactPrimary fix
Server-side template injection (CWE-1336)Server template engineData access, file read, remote code executionNever build templates from input; sandbox and isolate user-authored templates
Client-side template injectionBrowser framework template engineScript execution in the user's browser, similar to XSSDo not mix server-rendered user content into client template scopes; output encoding. See the Cross-Site Scripting (XSS) Prevention Guide
Expression language injection (CWE-917)Framework expression evaluatorRemote code executionNever evaluate expressions built from input
CI expression injectionWorkflow expressions substituted into scriptsCommand execution on runnersPass values through environment variables. See the Command Injection Guide
Remote template injection (document attacks)Office applications loading a template from a URLMalware deliveryEmail and endpoint controls; a different problem despite the name

Where it shows up

  • Customisable notifications and documents: email templates, PDF and invoice generators, report builders, marketing tools and helpdesk macros.
  • CMS, wiki and collaboration platforms: theme and macro systems. The CISA KEV catalog lists Confluence CVE-2023-22527, which Atlassian rated CVSS 10.0, as an unauthenticated template injection leading to remote code execution; Atlassian published the advisory on 16 January 2024 and fixed it in 8.5.4 and later.
  • File servers and appliances: in the local KEV snapshot used for this guide (catalog 2026.10.21), three entries are tagged CWE-1336, including CVE-2024-23692 in Rejetto HTTP File Server (unauthenticated command execution) and CVE-2024-4040 in CrushFTP (virtual file system sandbox escape). Many template-related KEV entries carry broader CWE tags such as CWE-74 or CWE-94, so the true count is higher.
  • AI and LLM applications: prompt templates are often rendered with Jinja2. CWE lists CVE-2024-34359, in which LLM Python bindings parsed model-supplied chat templates without sandboxing, as an observed SSTI example. Treat model metadata and model output as untrusted input. See the MCP Security Guide.
  • Low-code and workflow platforms: expressions in automations and integrations that interpolate record fields into templates.

Impact

  • Remote code execution on the rendering host, typically mapped to ATT&CK T1190 Exploit Public-Facing Application followed by T1059 Command and Scripting Interpreter.
  • Secret exposure: templates frequently have access to configuration objects, environment variables or settings holding database passwords, signing keys and API tokens (T1552.001 Credentials In Files covers the file case). CWE lists CVE-2018-20465 as an SSTI that exposed database credentials.
  • Persistence: a malicious stored template is itself a persistence mechanism, and execution allows web shells (T1505.003).
  • Denial of service: both the Jinja and FreeMarker documentation warn that a small template can consume large amounts of output, CPU or memory.

For executives the business question is simple: any feature that lets customers or staff edit templates is a code execution feature, and needs the same design review, isolation and ownership as one. Where identity fits: the rendering service's identity and secrets set the blast radius, so give it a dedicated, low-privilege service account with short-lived credentials. See the Service Account Security Guide.

Detection

In code review and testing

  • Find template compilation from strings: search for engine APIs that compile or render a template from a string rather than a file (for example rendering from a string in Jinja2, Twig or FreeMarker), and trace whether any part comes from request data, the database or model output.
  • Inventory user-authored template features and record which engine, configuration and sandbox each uses.
  • Test every reflected and stored field that is later rendered, including asynchronous outputs such as emails and PDFs, using engine-agnostic polyglot probes in a test environment. See the Web Application Security Testing Guide.
  • Check dependencies: SCA alerts for template engines and frameworks matter, since sandbox bypasses are fixed in engine releases.

At runtime

SignalSourceNotes
Application runtime (java, python, php-fpm, node) spawning shells or system utilitiesEDR, Sysmon Event ID 1, Windows event 4688, auditd execveD3FEND D3-PSA Process Spawn Analysis; highest-confidence signal
Template engine errors: SecurityError, sandbox violations, unknown attribute errorsApplication logsJinja raises SecurityError on blocked access; spikes indicate probing
Template edits by unusual accounts or at unusual timesApplication audit logTreat template changes like code changes
Rendering hosts making unexpected outbound connectionsEgress proxy, DNS, flow logsBlind SSTI and exfiltration
Rendering jobs with abnormal CPU, memory or output sizeContainer and APM metricsResource abuse or failed exploitation

See the Detection Engineering Guide for turning these into tested rules.

Prevention and hardening

Decision guidance: what to allow

RequirementRecommended designTrade-offs
Developers own all templates; users supply valuesTemplates from files only; user input passed as context data; autoescaping onNo trade-off; this is the baseline
Users need placeholders in text (for example a name in an email)A small substitution format with a fixed list of placeholders, or a logic-less engine such as MustacheLess flexible; removes code execution paths
Trusted administrators need logic in templatesFull engine in sandbox mode, restricted object exposure, change approval and auditSandbox bypasses remain possible; needs isolation
Untrusted tenants or the public author templatesSandboxed engine inside an isolated, network-restricted, short-lived container with no secretsHighest cost; the only defensible option at this trust level

OWASP ASVS 5.0 V1.3.7 requires that templates are not built from untrusted input, and where there is no alternative, that untrusted input included during template creation is sanitised or strictly validated. V1.3.5 requires user-supplied scriptable or expression template content (such as Markdown, CSS or XSL stylesheets and BBCode) to be sanitised or disabled.

Engine configuration

  • Jinja2: use SandboxedEnvironment or ImmutableSandboxedEnvironment for any untrusted template. The sandbox blocks private and internal attributes and raises SecurityError, and can be tightened by overriding is_safe_attribute() and is_safe_callable(). The documentation warns that templates can still produce very large output, so set CPU and memory limits, and that rendering errors must be caught.
  • FreeMarker: the project FAQ says users should not be allowed to upload templates unless they are application developers. Where they must, use a DefaultObjectWrapper with a WhitelistMemberAccessPolicy, keep ?api disabled (the default), set the class resolver to ALLOWS_NOTHING_RESOLVER (the FAQ says SAFER_RESOLVER is not restrictive enough), and restrict the template loader. FreeMarker cannot enforce CPU or memory limits, so isolate it.
  • Other engines: CWE recommends choosing an engine that offers a sandbox or restricted mode and using it. Disable features that load files, call static methods or instantiate classes, and keep autoescaping on.
  • Context hygiene: pass plain values (strings, numbers, lists of plain records), never service objects, ORM sessions, request objects or configuration objects.
  • Isolation: render user-authored templates in a separate process or container with no credentials, no outbound network, a read-only file system and strict timeouts. MITRE D3FEND D3-EAL Executable Allowlisting on rendering hosts limits what a breakout can run.

Rollout plan

  1. Inventory: list every template engine, every string-compiled template and every feature where users author templates, with owners.
  2. Fix construction bugs first: refactor any code that formats input into template source so that input moves into the render context. This is usually a small change.
  3. Classify user-authored features by trust level using the decision table and set a target design for each.
  4. Enable sandboxing in staging, render the existing template corpus and log every violation; fix legitimate templates before enforcing in production. Keep the previous configuration behind a feature flag for rollback.
  5. Move untrusted rendering into isolated workers and remove secrets from their environment.
  6. Add guardrails: SAST rules blocking string-compiled templates outside an approved module, and process spawn alerts on rendering services.

Small and large organisations: smaller teams should avoid user-authored logic entirely and offer fixed placeholders; platforms that sell template customisation need the isolated rendering tier and a security review for every engine upgrade.

Measuring progress

  • Templates compiled from strings that include external data, trending to zero.
  • Percentage of user-authored template features running sandboxed and isolated.
  • Time to upgrade template engines after a security release.
  • Number of sandbox violations and rendering-process spawn alerts, investigated within SLA.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev. 5SI-10 Information Input Validation; SC-39 Process Isolation; AC-6 Least Privilege; SA-11 Developer Testing and Evaluation; SI-4 System MonitoringValidation, isolation, testing, monitoring
NIST CSF 2.0PR.PS-06; DE.CM-09Secure development and runtime monitoring
OWASP ASVS 5.0V1.3.7, V1.3.5Verification requirements
ISO/IEC 27001:2022Annex A 8.28 Secure codingPolicy anchor
MITRE ATT&CKT1190, T1059, T1505.003, T1552.001Detection engineering
MITRE D3FENDD3-PSA, D3-EALCountermeasures

Lessons from incidents

  • Collaboration platforms are high-value targets. Confluence CVE-2023-22527 needed no authentication and Atlassian listed no workaround, only upgrading. Keep internet-facing platforms with template or expression engines on the fastest patch track.
  • Expression interpolation into execution contexts recurs outside web apps. In the Ultralytics PyPI compromise of 2024, a branch name was inserted directly into a shell command in a CI workflow. It is command injection rather than SSTI, but the root cause is identical: untrusted text placed inside something that is evaluated, instead of passed as data.
  • AI components inherit the problem. The LLM bindings case listed by CWE shows that model files and chat templates are untrusted input.

Practitioner checklist

  • Inventory template engines, string-compiled templates and user-authored template features, with owners.
  • Refactor any template built from input so the input is passed as render context data.
  • Offer fixed placeholders or a logic-less engine wherever users only need substitution.
  • Run any user-authored template in the engine's sandbox with a restrictive object and class policy.
  • Render untrusted templates in isolated workers with no secrets, no outbound network and resource limits.
  • Expose only plain data to templates, never service, request or configuration objects.
  • Log sandbox violations and template changes, and alert on rendering processes spawning shells.
  • Track template engine security releases and patch internet-facing platforms with template flaws first.

Standards and references

Related NHI Mgmt Group resources: Command Injection Guide · Path Traversal Guide · Insecure Deserialisation Guide · Secure Coding Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.