diff --git a/.changeset/load-config-without-eval.md b/.changeset/load-config-without-eval.md new file mode 100644 index 00000000000..e0e5e58f5db --- /dev/null +++ b/.changeset/load-config-without-eval.md @@ -0,0 +1,5 @@ +--- +"webpack-cli": patch +--- + +chore: load configuration files with `import()` instead of `eval` diff --git a/packages/webpack-cli/src/webpack-cli.ts b/packages/webpack-cli/src/webpack-cli.ts index 12eae0a3794..250cd0558bf 100644 --- a/packages/webpack-cli/src/webpack-cli.ts +++ b/packages/webpack-cli/src/webpack-cli.ts @@ -3338,9 +3338,8 @@ class WebpackCLI { let loadingError; try { - options = // eslint-disable-next-line no-eval - (await eval(`import("${isFileURL ? configPath : pathToFileURL(configPath)}")`)) - .default; + options = (await import(isFileURL ? configPath : pathToFileURL(configPath).href)) + .default; } catch (err) { if (this.isValidationError(err) || process.env?.WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG) { throw err; diff --git a/test/build/config/basic/basic-config.test.js b/test/build/config/basic/basic-config.test.js index 4f861f55f71..b7f44998d05 100644 --- a/test/build/config/basic/basic-config.test.js +++ b/test/build/config/basic/basic-config.test.js @@ -1,5 +1,8 @@ "use strict"; +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); const { resolve } = require("node:path"); const { pathToFileURL } = require("node:url"); const { cleanStderr, run } = require("../../../utils/test-utils"); @@ -40,6 +43,24 @@ describe("basic config file", () => { expect(stdout).toBeTruthy(); }); + it("should load a configuration path as a module specifier and not run it as code", async () => { + const marker = path.join( + fs.mkdtempSync(path.join(os.tmpdir(), "webpack-cli-config-path-")), + "executed", + ); + const configPath = `file:///webpack.config.js"),require("node:fs").writeFileSync(${JSON.stringify(marker)},""),import("file:///webpack.config.js`; + + try { + const { exitCode, stderr } = await run(__dirname, ["-c", configPath]); + + expect(exitCode).toBe(2); + expect(stderr).toContain("Failed to load"); + expect(fs.existsSync(marker)).toBe(false); + } finally { + fs.rmSync(path.dirname(marker), { recursive: true, force: true }); + } + }); + it("should build and not throw error with a basic using weird path", async () => { const { exitCode, stderr, stdout } = await run(__dirname, [ "-c",