Server-side template injections are a serious threat when you’re building web apps with templating engines like EJS. In 2023, security researchers reported an issue in the EJS JavaScript template engine, tracked as CVE-2023-29827. The vulnerability was specifically related to how EJS v3.1.9 handles the closeDelimiter parameter.

If you’re curious about whether your app could be affected, how this works, or if it’s a real risk, this guide is for you. We’ll break down the risk, show some proof-of-concept code, discuss why this CVE is controversial (“disputed”), and give you practical advice.

What is EJS and Why Does It Matter?

EJS (Embedded JavaScript) is a popular templating engine for Node.js, letting you generate HTML with plain JavaScript.

A typical EJS render looks like this

const ejs = require('ejs');
const template = '<h1>Hello, <%= user %>!</h1>';
const html = ejs.render(template, { user: 'Alice' });
console.log(html);
// Output: <h1>Hello, Alice!</h1>

Developers commonly use EJS to craft dynamic pages. But if attackers control the template or inject code, they might execute arbitrary JS on your server.

EJS lets you adjust the delimiters used in the templates. For example, you can set closeDelimiter

ejs.render(str, data, { delimiter: '?', closeDelimiter: ')' });

According to the CVE

> If an attacker controls the EJS file (the template), template injection can be done through settings for closeDelimiter.

Source:
- GitHub Security Advisory
- Snyk Vulnerability DB

To illustrate, here’s a simple Node.js demo

const ejs = require('ejs');

// Normally trusted template, but here simulating attacker control:
const maliciousTemplate = '<%= process.mainModule.require("child_process").execSync("ls").toString() %>';

const options = {
  closeDelimiter: ')'
};

// This renders malicious code if template is attacker-controlled!
const result = ejs.render(maliciousTemplate, {}, options);
console.log(result);

This code would execute a shell command on your server if someone gave you that template! The focus of CVE-2023-29827 was that with a crafted delimiter (like )), certain parsing tricks may slip in, even past basic validation.

If you do, you’re giving attackers the whole arsenal of JavaScript—not just template injection.

You can read the vendor’s response in the official issue thread.

Understanding the Real-World Impact

Yes, the exploit works—IF you let users submit their own EJS templates (which is already unsafe). The weakness isn’t so much in EJS as it is in trusting untrusted input.

Best Practice:

Only interpolate safe, sanitized data.

If you must let users have some creative control, use a safer templating engine or sandbox heavy logic.

Further Reading

- NVD entry for CVE-2023-29827
- GitHub Advisory
- EJS repo
- OWASP: Server-Side Template Injection

[ ] Don’t let users submit templates

- [ ] Don’t pass EJS files/strings from untrusted sources to ejs.render

[ ] Review any use of custom delimiters for parsing quirks

Remember: The power of EJS comes with the responsibility to use it safely. If you only render your own, locked-down templates and interpolate safe data, you will not be affected by CVE-2023-29827.

Timeline

Published on: 05/04/2023 14:15:00 UTC
Last modified on: 05/19/2023 05:15:00 UTC