Server Side Template Injection on Aws
How Server Side Template Injection Manifests in Aws
Server Side Template Injection (SSTI) in Aws applications typically occurs when user input is embedded directly into template files without proper sanitization. In Aws Lambda functions using Node.js, this often happens with template engines like Handlebars, Mustache, or EJS when rendering dynamic content.
Consider this vulnerable Aws Lambda function using EJS:
const ejs = require('ejs');
exports.handler = async (event) => {
const template = `<h1>Hello <%= name %></h1>`;
const output = ejs.render(template, { name: event.queryStringParameters.name });
return {
statusCode: 200,
body: output
};
};The vulnerability emerges when attackers can control the name parameter. In EJS, this allows arbitrary code execution through JavaScript expressions. An attacker could send:
?name=<%= process.mainModule.require('child_process').execSync('id') %>This executes system commands on the Lambda runtime, potentially exposing environment variables, AWS credentials from the instance metadata service, or other sensitive data.
Another common pattern in Aws serverless applications uses Handlebars with user-controlled partials:
const Handlebars = require('handlebars');
exports.handler = async (event) => {
const source = `{{> userContent}}`;
const template = Handlebars.compile(source);
const output = template({}); // userContent comes from event
return { statusCode: 200, body: output };
};If userContent isn't properly validated, attackers can inject Handlebars expressions that execute arbitrary JavaScript in the Node.js runtime environment.
Aws Amplify applications using React with template literals are also vulnerable:
import React from 'react';
function UserProfile({ user }) {
return ({user.name}
);
}
If user.name contains template expressions, React's JSX parser will execute them during rendering, leading to XSS and potential SSTI in the browser context.
The AWS Lambda execution environment itself can be targeted. Lambda functions run with specific IAM roles and have access to AWS APIs. SSTI can be used to enumerate AWS resources:
?name=<%= require('aws-sdk').Lambda.listFunctions().promise().then(f => f.Functions.map(f => f.FunctionName).join(',')) %>This lists all Lambda functions accessible to the compromised function's IAM role, potentially exposing the application's architecture.
Aws-Specific Detection
Detecting SSTI in Aws environments requires both static analysis and runtime scanning. middleBrick's black-box scanning approach is particularly effective for serverless applications since it doesn't require access to source code or deployment credentials.
For Aws Lambda functions, middleBrick tests for SSTI by injecting template-specific payloads into parameters and analyzing responses. The scanner attempts to trigger template engine evaluation by sending inputs like:
{{7*7}} // Handlebars/Mustache
2+3 // EJS basic math
${7*7} // Freemarker
${{7*7}} // Jinja2When scanning Aws Amplify or serverless applications, middleBrick examines HTTP responses for template evaluation artifacts. Successful SSTI payloads will cause the server to return calculated values instead of the raw input.
middleBrick's API security scanning includes specific checks for:
| Template Engine | Payload Pattern | Aws Context |
|---|---|---|
| EJS | <%= 2+3 %> | Node.js Lambda |
| Handlebars | {{2+3}} | Serverless apps | Mustache | {{2+3}} | Static site generation |
| Freemarker | ${2+3} | Java-based Aws services |
For Aws-specific detection, middleBrick also tests for SSRF via template injection, attempting to access the instance metadata service:
?name=<%= require('https').get('http://169.254.169.254/latest/meta-data/iam/security-credentials/', (res) => { /* capture creds */ }) %>This payload targets the AWS metadata endpoint (169.254.169.254) to extract IAM credentials that could be used to access other AWS resources.
middleBrick's scanning process for Aws applications includes:
- Template engine fingerprinting through response analysis
- Payload injection with basic arithmetic and function calls
- Detection of AWS SDK usage in responses
- Testing for IAM credential exposure
- Checking for cross-service API calls
The scanner generates a security risk score (A-F) based on the severity and exploitability of any SSTI findings, with specific remediation guidance for Aws environments.
Aws-Specific Remediation
const ejs = require('ejs');
const sanitize = require('sanitize-html');
exports.handler = async (event) => {
const cleanName = sanitize(event.queryStringParameters.name, {
allowedTags: [],
allowedAttributes: {}
});
const template = `<h1>Hello <%= name %></h1>`;
const output = ejs.render(template, { name: cleanName });
return { statusCode: 200, body: output };
};For Handlebars templates in Aws serverless applications, use a custom helper registry that blocks dangerous functions:
const Handlebars = require('handlebars');
const safeHelpers = Handlebars.create();
safeHelpers.registerHelper('safeEcho', function (text) {
return new safeHelpers.SafeString(text);
});
exports.handler = async (event) => {
const source = `{{safeEcho name}}`;
const template = safeHelpers.compile(source);
const output = template({ name: event.queryStringParameters.name });
return { statusCode: 200, body: output };
};Aws Amplify applications should use Content Security Policy (CSP) headers to mitigate XSS from template injection:
exports.handler = async (event) => {
const output = /* render template */;
statusCode: 200,
headers: {
'Content-Security-Policy':