Skip to content

Server-side template injection (SSTI)

Server-side template injection (SSTI)

Description

SSTI, or Server-Side Template Injection, is a security vulnerability that occurs when an attacker can inject malicious code into a template engine. Template engines are commonly used in web applications to generate dynamic content, and SSTI occurs when user input is not properly validated or sanitized before being included in a template.

# Assume user_input contains user-controlled data
user_input = params[:input]

# Unsafe usage of ERB
template = ERB.new("<%= #{user_input} %>")
result = template.result(binding)

# Output the result
puts result
// Vulnerable PHP code using Twig
$name = $_GET['name'];
echo $twig->render('greet.twig', ['name' => $name]);
# Vulnerable Python code using Jinja2
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/greet')
def greet():
    # Injecting user input directly into the template
    username = request.args.get('username')
    return render_template('greet.html', username=username)

Recommendation

  • Avoid creating templates from user input whenever possible
  • Consider using a simple logic-less template engine such as Mustache
  • Render templates in a sandbox environment where risky modules and features are disabled.
  • Sanitize user input before passing it into the template

Examples

# app.rb
require 'sinatra'
require 'mustache'

class ExampleTemplate < Mustache
  def initialize(name)
    @name = name
  end

  def greeting
    "Hello, #{@name}!"
  end
end

get '/greet/:name' do
  name = params['name']
  template = ExampleTemplate.new(name)
  erb template.render
end
<!-- index.php -->
<?php
require 'Mustache/Autoloader.php';
Mustache_Autoloader::register();

$template = new Mustache_Engine;

$name = $_GET['name'] ?? 'World';
$data = ['name' => $name];
echo $template->render('Hello, {{name}}!', $data);
?>
from flask import Flask, render_template
from flask import request
import pystache

app = Flask(__name__)

# Define a simple Mustache template
template = """
<html>
<head>
    <title>Greeting Page</title>
</head>
<body>
    <h1>Hello, {{name}}!</h1>
</body>
</html>
"""

# Create a Mustache renderer
mustache_renderer = pystache.Renderer()

@app.route('/')
def greet_user():
    # Get the 'name' query parameter from the URL
    user_name = request.args.get('name', 'Guest')

    # Render the template with the user's name
    rendered_template = mustache_renderer.render(template, {'name': user_name})

    # Return the rendered HTML
    return rendered_template

if __name__ == '__main__':
    app.run(debug=True)

Standards

  • CWE_TOP_25:
    • CWE_94
  • GDPR:
    • ART_5
    • ART_32
  • PCI_STANDARDS:
    • REQ_6_5
    • REQ_11_3
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_3_4
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5