Back to Blog
high SEVERITY6 min read

How Arbitrary Code Execution via Template Imports Happens in JavaScript (lodash) and How to Fix It

A high-severity arbitrary code execution vulnerability (CVE-2026-4800) was discovered in lodash's template function, specifically in how it handles the `imports` option with untrusted input. The fix upgrades lodash from version 4.17.21 to 4.18.0 in the project's `package.json` and `yarn.lock`, eliminating the attack surface where crafted template imports could execute arbitrary code on the server.

O
By Orbis AppSec
Published August 8, 2026Reviewed August 8, 2026

Answer Summary

CVE-2026-4800 is a high-severity arbitrary code execution vulnerability in lodash (JavaScript) affecting the `_.template()` function's `imports` option, related to CWE-94 (Improper Control of Generation of Code). When untrusted input flows into template imports, an attacker can inject and execute arbitrary JavaScript code. The fix is to upgrade lodash from 4.17.21 to 4.18.0, which sanitizes and restricts what can be passed through template imports.

Vulnerability at a Glance

cweCWE-94 (Improper Control of Generation of Code / Code Injection)
fixUpgrade lodash from 4.17.21 to 4.18.0 which adds proper validation of template import inputs
riskRemote code execution on the server through crafted template import payloads
languageJavaScript (Node.js)
root causelodash `_.template()` does not sufficiently sanitize the `imports` option, allowing injected code to execute during template compilation
vulnerabilityArbitrary Code Execution via Template Imports

Introduction

In the kitsu-season-trends project, Orbis AppSec detected a high-severity arbitrary code execution vulnerability (CVE-2026-4800) lurking in the project's dependency tree. The yarn.lock file pinned lodash at version 4.17.21, which contains a critical flaw in how _.template() processes the imports option. This vulnerability allows an attacker to inject and execute arbitrary JavaScript code when untrusted data flows into template compilation—a scenario that could lead to full remote code execution (RCE) on the server.

The project uses lodash as a transitive dependency through its Babel toolchain (@babel/cli, @babel/core, @babel/node, etc.), meaning the vulnerable code is present in the dependency graph even if the application doesn't directly call _.template(). Any code path—including build tools, server-side rendering, or utility functions—that compiles lodash templates with externally-influenced data is at risk.

The Vulnerability Explained

How _.template() Imports Work

Lodash's _.template() function compiles template strings into executable JavaScript functions. It accepts an options object with an imports property that defines variables available within the template scope:

const compiled = _.template('Hello <%= user %>!', {
  imports: { user: 'World' }
});

Internally, lodash constructs a Function object using the template string and import keys. In lodash 4.17.21 and earlier, the imports option's keys and values are insufficiently validated before being interpolated into the generated function body.

The Attack Vector

An attacker who can influence the imports option—whether through user input, configuration files, or API parameters—can craft a payload that breaks out of the template context:

// Attacker-controlled input flowing into template imports
const maliciousImports = {
  'constructor': { 'prototype': { 'toString': function() { 
    return require('child_process').execSync('whoami').toString(); 
  }}}
};

// Or more directly via crafted key names:
const payload = {
  'x; process.mainModule.require("child_process").execSync("cat /etc/passwd")//': ''
};

_.template('<%= x %>', { imports: payload });

When lodash compiles this template, the injected code executes during the function construction phase—before the template is even "called." This means the mere act of compiling a template with tainted imports triggers code execution.

Real-World Impact for This Project

In the kitsu-season-trends project, lodash is pulled in through the Babel ecosystem. Consider these attack scenarios:

  1. Build-time exploitation: If any build script or Babel plugin uses _.template() with configuration values sourced from external files (e.g., environment variables, JSON configs pulled from a registry), an attacker who compromises those sources gains code execution during the build process.

  2. Supply chain attack: A malicious dependency in the node_modules tree could call _.template() with crafted imports, executing arbitrary code when the project is built or run via @babel/node.

  3. Server-side rendering: If the application renders templates server-side with any user-influenced data flowing into the imports option, it becomes a direct RCE vector.

The Fix

The fix upgrades lodash from 4.17.21 to 4.18.0 by modifying two files:

package.json Change

The lodash dependency version constraint is updated to require 4.18.0 or compatible:

// Before
"lodash": "^4.17.21"

// After  
"lodash": "^4.18.0"

yarn.lock Change

The lockfile is regenerated to resolve lodash at the new patched version. The project also migrated to Yarn's Plug'n'Play (PnP) system, as evidenced by the new .pnp.cjs file that manages dependency resolution without a traditional node_modules directory:

// .pnp.cjs - Dependency resolution now points to lodash 4.18.0
"packageRegistryData": [
  // ... all dependencies including patched lodash resolved here
]

What lodash 4.18.0 Changes Internally

The patched version adds validation to the _.template() function's imports processing:

  1. Key sanitization: Import keys are now validated against a strict identifier pattern, preventing injection of code through crafted property names.
  2. Value type checking: Import values are type-checked before interpolation into the generated function body.
  3. Function constructor hardening: The internal Function() call that compiles templates now uses proper escaping to prevent breakout from the intended template scope.

Why Both Files Changed

  • package.json: Declares the intent to use lodash ≥4.18.0, ensuring future installs pull the patched version.
  • yarn.lock (and .pnp.cjs): Locks the exact resolved version, guaranteeing reproducible builds with the security fix in place. The PnP migration adds an additional layer of supply chain integrity by eliminating the mutable node_modules directory.

Prevention & Best Practices

1. Never Pass Untrusted Input to Template Options

// DANGEROUS: User input flows into template imports
_.template(templateStr, { imports: userProvidedObject });

// SAFE: Only use hardcoded, trusted imports
_.template(templateStr, { imports: { _: lodash, moment: moment } });

2. Keep Dependencies Updated

Use automated dependency scanning to catch known vulnerabilities:

# Scan with Trivy
trivy fs --scanners vuln .

# Or with npm audit
npm audit --production

3. Use Lockfile Integrity Checks

Ensure your CI/CD pipeline validates lockfile integrity:

# In your CI configuration
- run: yarn install --immutable  # Fails if lockfile is out of date

4. Prefer Sandboxed Template Engines

For user-facing templates, consider engines with built-in sandboxing (Handlebars with strict mode, Nunjucks with sandboxed environment) rather than lodash templates.

5. Apply the Principle of Least Privilege

Run build processes and server applications with minimal permissions so that even if code execution occurs, the blast radius is limited.

Key Takeaways

  • lodash _.template() with untrusted imports is equivalent to eval() — the imports option directly influences generated function code, making it a code injection sink.
  • Transitive dependencies matter: Even though kitsu-season-trends uses lodash primarily through Babel, the vulnerable code is still present and exploitable in the dependency graph.
  • Lockfile pinning alone doesn't protect you: The yarn.lock pinned lodash at 4.17.21 for reproducibility, but that same pinning prevented automatic security updates—active dependency management is required.
  • Build-time vulnerabilities are real attack surfaces: Code execution during yarn install or babel compilation is just as dangerous as runtime exploitation.
  • The .pnp.cjs migration adds supply chain hardening: By eliminating node_modules hoisting, Yarn PnP prevents phantom dependencies and makes the dependency graph more auditable.

How Orbis AppSec Detected This

  • Source: External data flowing into lodash _.template() options, specifically the imports parameter that accepts object properties as template-scope variables.
  • Sink: _.template() internal Function() constructor in lodash 4.17.21, which compiles import keys/values into executable JavaScript without sufficient sanitization.
  • Missing control: No validation or sanitization of import keys and values before they are interpolated into the generated function body—allowing arbitrary code injection through crafted property names.
  • CWE: CWE-94 (Improper Control of Generation of Code / Code Injection)
  • Fix: Upgraded lodash from 4.17.21 to 4.18.0, which adds strict validation of template import keys and proper escaping in the function constructor.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-4800 demonstrates how a widely-used utility library like lodash can harbor critical code execution vulnerabilities in seemingly innocuous features. The _.template() function's imports option—designed for convenience—became an arbitrary code execution vector when untrusted input could reach it. By upgrading to lodash 4.18.0 and adopting Yarn PnP for tighter dependency resolution, this project eliminated both the immediate vulnerability and improved its overall supply chain security posture.

For developers: treat template compilation options with the same caution you'd give eval(). Audit your dependency trees regularly, and leverage automated scanning tools to catch known CVEs before they reach production.

References

Frequently Asked Questions

What is arbitrary code execution via template imports?

It's a vulnerability where an attacker can inject executable code through the `imports` option of lodash's `_.template()` function. When the template is compiled, the injected code runs with the same privileges as the application, potentially giving full server access.

How do you prevent template injection in JavaScript?

Never pass untrusted user input to `_.template()` options (especially `imports`), upgrade to lodash 4.18.0+, use template engines with sandboxed execution, and validate all data that flows into template compilation.

What CWE is arbitrary code execution via template imports?

CWE-94 (Improper Control of Generation of Code), which covers situations where software constructs code segments using externally-influenced input without proper neutralization.

Is input validation enough to prevent template code injection?

Input validation helps but is not sufficient alone. The safest approach is to upgrade to a patched version (lodash 4.18.0+) that handles sanitization internally, combined with never passing user-controlled data to template compilation options.

Can static analysis detect template code injection?

Yes, tools like Trivy, Snyk, and Semgrep can detect known vulnerable versions of lodash and flag patterns where untrusted input flows into `_.template()`. Trivy specifically flagged this CVE in the project's `yarn.lock`.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #709

Related Articles

critical

How Sensitive Data Exposure in Error Logging happens in TypeScript/Deno and how to fix it

A critical vulnerability in Supabase Edge Functions allowed sensitive authentication errors and API credentials to leak through verbose error logging. The `cancel-subscription/index.ts` function logged full error objects to the console, potentially exposing Paddle API keys and auth tokens in deployment logs. The fix sanitizes all error messages to log only safe error text while preserving debugging capability.

critical

How HTTP Header Injection Happens in Go and How to Fix It

A critical vulnerability in the file upload handler allowed attackers to inject CRLF sequences into HTTP response headers through crafted filenames. The fix sanitizes user-supplied filenames before using them in Content-Disposition headers, preventing header injection attacks that could lead to cache poisoning, session fixation, or XSS.

high

How Path Traversal and Security Policy Bypass Happens in Node.js Dependencies and How to Fix It

A high-severity vulnerability in the fast-uri package (CVE-2026-6321) allowed attackers to bypass security policies through improper Unicode hostname canonicalization and path traversal. This issue affected the @apralabs/apra-fleet project through its dependency tree, and was resolved by upgrading fast-uri from version 3.1.0 to 4.1.2 using npm overrides.

high

How Command Injection happens in Node.js child_process calls and how to fix it

A high-severity command injection vulnerability was discovered in `tools/utils/lang/helpers.ts` where the `prettier()` function passed a user-controllable `fileName` argument directly into a shell command string via `exec()`. By replacing `exec()` with `execFile()` and passing arguments as an array, the fix eliminates shell interpolation entirely, preventing attackers from injecting arbitrary shell commands through malicious filenames.

high

How Quadratic CPU Consumption in YAML Parsing happens in JavaScript and how to fix it

A high-severity vulnerability in js-yaml versions 3.x and 4.x allowed attackers to cause quadratic CPU consumption through specially crafted YAML documents using the `!!omap` type. This denial-of-service vulnerability (GHSA-5p4m-2wfm-xmqj) was fixed by upgrading from js-yaml 4.3.0 to 4.3.1, protecting applications from algorithmic complexity attacks during YAML parsing.

high

How Arbitrary HTTP Header Injection via Prototype Pollution happens in JavaScript and how to fix it

A high-severity vulnerability (CVE-2026-42035) in axios version 1.13.5 allowed attackers to inject arbitrary HTTP headers through prototype pollution. The fix upgrades axios to version 1.18.0 in the frontend's dependency tree, which includes proper prototype chain validation when constructing HTTP request headers. This prevents attackers from manipulating outgoing requests to perform SSRF, session hijacking, or cache poisoning attacks.