Safeguard
Open Source

Using EJS on npm Safely: CVE-2022-29078 and Beyond

The ejs npm package is a capable template engine that has also been the subject of a serious RCE advisory. Here is how to use it without opening that door.

Marcus Chen
DevSecOps Engineer
5 min read

The ejs npm package is safe to use on version 3.1.7 or later, but earlier 3.x releases carry CVE-2022-29078, a server-side template injection flaw that can lead to remote code execution — so pinning a patched version and never passing untrusted input into template options are non-negotiable. EJS (Embedded JavaScript) is a lightweight template engine used across countless Express apps, and its convenience is exactly why the RCE advisory against it deserves attention.

If you already depend on npm ejs, the first thing to do is check your installed version:

npm ls ejs

Anything in the 3.0.1 through 3.1.6 range is affected by the advisory below. Anything 3.1.7 or higher has the fix.

What CVE-2022-29078 actually is

CVE-2022-29078 is a server-side template injection (SSTI) vulnerability in EJS. The details, per the GitHub Advisory and Snyk's writeup: EJS parsed the settings[view options][outputFunctionName] value as an internal option, which let an attacker overwrite the outputFunctionName option with an arbitrary OS command that executes when the template is compiled.

An important qualifier that is often dropped: exploitation depends on the application already being vulnerable to prototype pollution, which is what lets attacker-controlled data reach those internal EJS options. In other words, CVE-2022-29078 is the second link in a chain, not a one-shot. That does not make it safe to ignore — prototype pollution is common enough that treating the two as a combined risk is the right posture.

The fix landed in EJS 3.1.7, which stopped treating that view option as a code-execution vector.

The remediation is simple: upgrade

Unlike some vulnerabilities that require code changes, this one is fixed by moving to a patched release:

npm install ejs@latest
# verify
npm ls ejs

Confirm you land on 3.1.7 or newer. If a transitive dependency pins an older ejs, use an override to force the patched version:

{
  "overrides": {
    "ejs": ">=3.1.7"
  }
}

Then reinstall and re-audit. npm audit will confirm the advisory is cleared from your tree.

Template injection is the broader risk

Fixing one CVE does not make template rendering inherently safe. The category behind CVE-2022-29078 — server-side template injection — recurs whenever untrusted input reaches the template engine as anything other than plain data. Two rules keep you clear of the whole class:

Never let user input choose or build the template. Templates are code. Render a fixed template file and pass user data in as variables:

// Safe: template path is fixed, user data is just a value
app.get('/profile', (req, res) => {
  res.render('profile', { name: req.query.name });
});
// Dangerous: user input becomes part of the template source
const tpl = `<h1>Hello ${req.query.name}</h1>`;
ejs.render(tpl, {});   // if name is attacker-controlled, this is SSTI

The second pattern compiles attacker input as template source. Never do it.

Do not spread untrusted objects into render options. The CVE worked through options, so passing a user-controlled object as EJS options — or anywhere it can pollute the prototype chain — is exactly the door to keep shut.

Escaping and XSS

EJS distinguishes escaped from unescaped output, and this is a client-side security boundary you control per tag:

  • <%= value %> HTML-escapes the value. This is the default and the safe choice.
  • <%- value %> outputs raw, unescaped. Only use it for content you fully trust and have already sanitized.

A common XSS foothold is reaching for <%- to render rich content and forgetting that the "rich content" originated from a user. If you must render user-supplied HTML, sanitize it with a dedicated library before it hits an unescaped tag.

Keep monitoring, not just patching

Upgrading ejs today does not protect you from the advisory published against it next year. Because a template engine sits on the request path, a future flaw in it is high-impact by definition. Continuous dependency monitoring means a new ejs advisory reaches you as an alert rather than as an incident. A software composition analysis tool such as Safeguard can flag a vulnerable ejs version transitively, even when it is buried under a dependency you installed for another reason. For the wider pattern of build-time dependency gates, the DevSecOps process guide covers where scanning fits in the pipeline.

Checklist for shipping EJS safely

  1. Pin ejs to >=3.1.7 and confirm with npm ls ejs.
  2. Add an override if a transitive dependency drags in an older version.
  3. Render fixed template files; never compile user input as template source.
  4. Default to escaped <%= output; treat <%- as an audited exception.
  5. Harden against prototype pollution, since it is the enabling condition for the CVE.
  6. Enable continuous SCA so future ejs advisories surface automatically.

FAQ

Is the ejs npm package safe to use?

Yes, on version 3.1.7 or later. Versions 3.0.1 through 3.1.6 are affected by CVE-2022-29078, a server-side template injection issue that can lead to remote code execution. Upgrade and pin to a patched release.

What is CVE-2022-29078?

It is an SSTI vulnerability in EJS where the outputFunctionName view option could be overwritten with an arbitrary OS command, executed at template compile time. Exploitation requires the app to also be vulnerable to prototype pollution. It was fixed in EJS 3.1.7.

How do I fix the EJS vulnerability?

Run npm install ejs@latest and confirm you are on 3.1.7 or higher. If a transitive dependency pins an older version, add an npm overrides entry forcing ejs >=3.1.7, then reinstall and re-run npm audit.

How do I prevent template injection in EJS?

Never render user input as template source — pass it only as data into a fixed template file. Avoid spreading untrusted objects into render options, default to the escaped <%= tag, and harden the app against prototype pollution.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.