Lodash users: upgrade to 4.18.0 now. Versions before it expose a code injection vulnerability in _.template() through untrusted keys in the options.imports object. Attackers inject arbitrary code at template compile time if you pass tainted input as property names.
This flaw builds on the incomplete fix for CVE-2021-23337, rated high severity (7.5/10 CVSS). That earlier issue blocked dangerous characters in the variable option but skipped validation for imports keys. Both options feed into JavaScript’s Function() constructor, which executes code directly. Supply keys with default-parameter syntax like foo=alert(1), and it runs during compilation.
Prototype pollution amplifies the risk. Lodash’s _.template uses assignInWith to merge imports, which loops over inherited properties via for...in. If Object.prototype carries attacker-controlled keys from elsewhere—like a prior gadget chain—those slip into the Function() args. Common in Node.js apps where user data touches global objects.
Why This Hits Hard
Lodash powers over 1.5 million npm packages and sees 500 million weekly downloads. Its templates compile HTML-like strings with Lodash syntax, often in servers rendering dynamic content. Think Express views or CLI tools. If your code does _.template(userTemplate, {imports: userProvidedImports}), you’re exposed. Even static setups risk pollution if another library dirties prototypes.
Real-world impact: remote code execution without eval-like flags. Compile-time means one bad template poisons the function forever. Node.js environments amplify this—servers recompiling user-supplied templates could execute shell commands. Browser-side? Less likely, but webpack bundles with lodash-es or lodash-amd inherit the bug.
Skeptical take: not every app uses imports dynamically. Most stick to safe, hardcoded helpers like {imports: {formatDate: myFunc}}. But surveys show 20% of JS projects still run lodash 4.17.x, per Snyk data. And prototype pollution chains succeed in 15-30% of tested Node apps. Combine with unpatched CVE-2021-23337 remnants, and it’s a chainable exploit.
How the Fix Works
Version 4.18.0, released March 2024, plugs both holes:
- Validates
importskeys againstreForbiddenIdentifierCharsregex—the same check now guardingvariable. Blocks specials like=or[used in default params. - Swaps
assignInWithforassignWith, limiting merges to own properties only. No more prototype leaks.
Update command:
npm install lodash@4.18.0
Or yarn/pnpm equivalents. Check your lockfile—subdependencies like lodash-es might lag. Tools like npm audit or Snyk flag GHSA-mq68-7v62-8jgp (this advisory’s ID).
Workarounds if patching delays:
- Hardcode
importskeys. Never user input. - Whitelist keys:
Object.keys(imports).forEach(k => { if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k)) delete imports[k]; }) - Sandbox templates or switch to safer alternatives like Handlebars (no Function sink).
Verify with a test:
// Vulnerable pre-4.18.0
const tmpl = _.template('<div><%= foo() %></div>', {
imports: { 'alert(1)': () => alert(1) } // Executes!
});
// Safe post-fix: throws validation error
What You Do Next
Scan deps today. Lodash 4.x lingers because it’s stable, but security trumps inertia. This vuln underscores JS’s prototype pitfalls—Function() remains a prototype pollution magnet. Broader lesson: audit template libs. Marked as high, but real score depends on your stack. Patch anyway; cost is one command, risk is RCE.
Track via GitHub advisory GHSA-mq68-7v62-8jgp. Lodash maintainers fixed fast—credit where due—but highlights why you audit, not trust.