Skip to main content
EJS Remote Code Execution: A 24-Hour FixIncident
4 min readFor Security Engineers

EJS Remote Code Execution: A 24-Hour Fix

What Happened

On November 27th, security researchers disclosed a high-severity Remote Code Execution vulnerability in EJS, a widely-used JavaScript templating engine. This vulnerability allowed attackers to manipulate the root option when data and options were combined into a single object, enabling arbitrary file includes. Project owner Matthew Eernisse released version 2.5.3 with a fix by November 28th—a one-day turnaround from disclosure to patch.

Timeline

Day 0 (November 27th)

  • Vulnerability disclosed to project maintainers
  • Issue identified: unsafe handling when data and options objects are merged
  • Attack vector confirmed: manipulation of root option for file includes

Day 1 (November 28th)

  • Fix developed and tested
  • Version 2.5.3 released
  • Security advisory published

Which Controls Failed or Were Missing

The incident exposed three control gaps that your team should examine in your own environment:

Input validation at the framework level. EJS accepted a combined data-options object without enforcing strict separation between user-controlled data and framework configuration. When your templating engine can't distinguish between "this is content to render" and "this is how to render it," you've created a privilege escalation pathway.

Secure-by-default configuration. The root option, which controls file system access for includes, could be overridden through user input. Any configuration parameter that touches file paths, network boundaries, or execution context should require explicit administrator action to change—not accept values from a data payload.

Dependency monitoring and update automation. Organizations running EJS had a 24-hour window to identify their exposure and deploy the patch. Without automated dependency scanning, you're relying on someone manually checking GitHub release notes or security mailing lists. That doesn't scale when you're managing dozens of dependencies across multiple applications.

What the Relevant Standards Require

PCI DSS v4.0.1 Requirement 6.3.2 mandates that software development practices include security throughout the software development life cycle. This includes secure coding techniques that prevent common vulnerabilities. The EJS issue—allowing configuration override through untrusted input—represents exactly the type of injection vulnerability this requirement targets.

OWASP Top 10 2021: A03:2021 – Injection directly addresses this failure mode. The standard specifically calls out scenarios where "hostile data is used within object-relational mapping (ORM) search parameters to extract additional, sensitive records" or where "hostile data is directly used or concatenated." Passing user-controlled data into framework options is a textbook injection risk.

OWASP ASVS v4.0.3 Section 5.2.8 requires that template engines "prevent Server-Side Template Injection by using a safe template engine or by ensuring that any user input being included is sanitized or sandboxed." The EJS vulnerability violated this control by allowing template configuration manipulation.

ISO/IEC 27001:2022 Annex A.8.8 (Management of technical vulnerabilities) requires you to obtain timely information about technical vulnerabilities, evaluate exposure, and take appropriate measures. A one-day disclosure-to-patch cycle means you need detection and deployment capabilities that operate on the same timeline.

Lessons and Action Items for Your Team

Map your templating engine exposure. Run npm list ejs or your package manager's equivalent across your repositories today. Don't assume you know where EJS is used—transitive dependencies matter. One of your teams might have pulled in a form builder that depends on EJS three layers deep.

Implement automated dependency scanning. Tools like Snyk, Dependabot, or npm audit should run on every commit and flag known vulnerabilities before code reaches production. Set up Slack or email alerts for high-severity issues. When a vulnerability drops at 3pm on a Friday, you need to know about it by 3:05pm, not Monday morning.

Establish a 24-hour patch SLA for critical vulnerabilities. The EJS maintainers proved a one-day fix is possible. Your deployment pipeline should match that speed. This means:

  • Automated testing that runs in minutes, not hours
  • Deployment automation that doesn't require manual approvals for security patches
  • A defined escalation path when a critical CVE hits

Audit your own framework code for similar patterns. If you maintain internal libraries or frameworks, search for anywhere you accept a combined configuration-plus-data object. Separate them. Make configuration explicit and data implicit. Never let user input flow into parameters that control file paths, network destinations, or code execution.

Test your incident response with a tabletop exercise. Pick a critical dependency—your ORM, your authentication library, your API framework. Simulate a high-severity disclosure. Can you identify all affected applications within one hour? Can you deploy a patch to production within 24 hours? If not, that's your next sprint's work.

Document your dependency update policy. Write down who has authority to emergency-patch production, what testing is required versus waived for security fixes, and how you communicate changes to dependent teams. When a real incident hits, you don't want to be drafting policy in Slack.

The EJS vulnerability didn't create headlines because it was fixed before attackers could weaponize it at scale. That's the goal: make your response faster than the exploit development cycle. A 24-hour window from disclosure to production deployment isn't aspirational—it's the baseline for managing modern application dependencies.

Topics:Incident

You Might Also Like