VYPR
High severity8.8OSV Advisory· Published Oct 31, 2024· Updated Apr 15, 2026

CVE-2024-21537

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.

PackageAffected versionsPatched versions
lilconfignpm
>= 3.1.0, < 3.1.13.1.1

Affected products

1

Patches

2
2c68a1ab8764

remove .d.ts from import paths

https://github.com/antonk52/lilconfigantonk52Feb 17, 2024via ghsa
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: '',
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.