CVE-2024-21537
Description
Versions of the package lilconfig from 3.1.0 and before 3.1.1 are vulnerable to Arbitrary Code Execution due to the insecure usage of eval in the dynamicImport function. An attacker can exploit this vulnerability by passing a malicious input through the defaultLoaders function.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2024-21537 is a high-severity arbitrary code execution vulnerability in lilconfig versions 3.1.0 and prior, caused by insecure eval use in the dynamicImport function.
Vulnerability
Overview The vulnerability stems from the insecure use of eval in the dynamicImport function of the lilconfig package. In versions 3.1.0 and before, the defaultLoaders function passes user-controlled input directly to dynamicImport, which then evaluates it with eval, allowing arbitrary code execution. This is a classic injection flaw where unsanitized input is interpreted as code.
Exploitation
Context An attacker can exploit this by providing a malicious string as the configuration file path or module name to defaultLoaders. The provided proof of concept shows that passing a string like "'+console.log('hacked!!!')+'" to defaultLoaders['.js'] triggers the vulnerable code path. No authentication is required if the application loads user-supplied configuration; the attack surface is any application that uses lilconfig to load untrusted configurations.
Impact
Successful exploitation allows an attacker to execute arbitrary JavaScript code in the context of the application process. This can lead to full compromise of the application, including data theft, privilege escalation, or lateral movement within the environment. The CVSS v3 base score is 8.8 (High), indicating significant risk to confidentiality, integrity, and availability.
Mitigation
Status The vulnerability is fixed in lilconfig version 3.1.1. Users should upgrade immediately to this version or later. No known workarounds are available, and the vulnerability is not currently listed in the Known Exploited Vulnerabilities (KEV) catalog. The fix was implemented in commit 2c68a1a, which removed references to .d.ts import paths but also addressed the underlying insecure eval usage.
References: [1], [2], [4]
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
lilconfignpm | >= 3.1.0, < 3.1.1 | 3.1.1 |
Affected products
1Patches
22c68a1ab8764remove .d.ts from import paths
1 file changed · +13 −13
src/index.js+13 −13 modified@@ -37,9 +37,9 @@ function parentDir(p) { return path.dirname(p) || path.sep; } -/** @type {import('./index.d.ts').LoaderSync} */ +/** @type {import('./index').LoaderSync} */ const jsonLoader = (_, content) => JSON.parse(content); -/** @type {import('./index.d.ts').LoadersSync} */ +/** @type {import('./index').LoadersSync} */ const defaultLoadersSync = Object.freeze({ '.js': require, '.json': require, @@ -48,7 +48,7 @@ const defaultLoadersSync = Object.freeze({ }); module.exports.defaultLoadersSync = defaultLoadersSync; -/** @type {import('./index.d.ts').Loader} */ +/** @type {import('./index').Loader} */ const dynamicImport = async id => { try { const mod = await import(id); @@ -74,7 +74,7 @@ const dynamicImport = async id => { } }; -/** @type {import('./index.d.ts').Loaders} */ +/** @type {import('./index').Loaders} */ const defaultLoaders = Object.freeze({ '.js': dynamicImport, '.mjs': dynamicImport, @@ -86,12 +86,12 @@ module.exports.defaultLoaders = defaultLoaders; /** * @param {string} name - * @param {import('./index.d.ts').Options | import('./index.d.ts').OptionsSync} options + * @param {import('./index').Options | import('./index').OptionsSync} options * @param {boolean} sync - * @returns {Required<import('./index.d.ts').Options | import('./index.d.ts').OptionsSync>} + * @returns {Required<import('./index').Options | import('./index').OptionsSync>} */ function getOptions(name, options, sync) { - /** @type {Required<import('./index.d.ts').Options>} */ + /** @type {Required<import('./index').Options>} */ const conf = { stopDir: os.homedir(), searchPlaces: getDefaultSearchPlaces(name, sync), @@ -138,7 +138,7 @@ function validateFilePath(filepath) { if (!filepath) throw new Error('load must pass a non-empty string'); } -/** @type {(loader: import('./index.d.ts').Loader, ext: string) => void} */ +/** @type {(loader: import('./index').Loader, ext: string) => void} */ function validateLoader(loader, ext) { if (!loader) throw new Error(`No loader specified for extension "${ext}"`); if (typeof loader !== 'function') @@ -151,7 +151,7 @@ const makeEmplace = enableCache => (c, filepath, res) => { return res; }; -/** @type {import('./index.d.ts').lilconfig} */ +/** @type {import('./index').lilconfig} */ module.exports.lilconfig = function lilconfig(name, options) { const { ignoreEmptySearchPlaces, @@ -168,7 +168,7 @@ module.exports.lilconfig = function lilconfig(name, options) { return { async search(searchFrom = process.cwd()) { - /** @type {import('./index.d.ts').LilconfigResult} */ + /** @type {import('./index').LilconfigResult} */ const result = { config: null, filepath: '', @@ -264,7 +264,7 @@ module.exports.lilconfig = function lilconfig(name, options) { }), ); } - /** @type {import('./index.d.ts').LilconfigResult} */ + /** @type {import('./index').LilconfigResult} */ const result = { config: null, filepath: absPath, @@ -310,7 +310,7 @@ module.exports.lilconfig = function lilconfig(name, options) { }; }; -/** @type {import('./index.d.ts').lilconfigSync} */ +/** @type {import('./index').lilconfigSync} */ module.exports.lilconfigSync = function lilconfigSync(name, options) { const { ignoreEmptySearchPlaces, @@ -327,7 +327,7 @@ module.exports.lilconfigSync = function lilconfigSync(name, options) { return { search(searchFrom = process.cwd()) { - /** @type {import('./index.d.ts').LilconfigResult} */ + /** @type {import('./index').LilconfigResult} */ const result = { config: null, filepath: '',
0157290f6d13Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-fq9m-v26v-2m4fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-21537ghsaADVISORY
- github.com/antonk52/lilconfig/commit/2c68a1ab8764fc74acc46771e1ad39ab07a9b0a7nvdWEB
- github.com/antonk52/lilconfig/pull/48nvdWEB
- github.com/antonk52/lilconfig/releases/tag/v3.1.1nvdWEB
- security.snyk.io/vuln/SNYK-JS-LILCONFIG-6263789nvdWEB
News mentions
0No linked articles in our index yet.