Skip to content

Commit 8ad7622

Browse files
fix(WorkerPlugin): sanitize webpackEntryOptions at the parse boundary
Move the prototype-pollution guard out of buildChunkGraph and into the place where the `webpackEntryOptions` magic comment is consumed: copy only safe own keys (skip `__proto__`/`constructor`/`prototype`) instead of `Object.assign`. This protects every consumer of the resulting entryOptions (the entrypoint constructor and the gap-fill) at the untrusted-input boundary, so buildChunkGraph no longer needs key validation and keeps only its `name`-identity exclusion. The existing worker test still asserts the keys never reach entrypoint.options.
1 parent 5fbee11 commit 8ad7622

2 files changed

Lines changed: 19 additions & 14 deletions

File tree

lib/buildChunkGraph.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -592,21 +592,12 @@ const visitModules = (
592592
// from a block that deduped in via its module would leave
593593
// `entrypoint.name` out of sync and make module codegen
594594
// order-dependent, which breaks persistent caching.
595-
// `entryOptions` may come from the `webpackEntryOptions` magic
596-
// comment, so reject prototype-polluting keys before assigning.
597595
const existingOptions = entrypoint.options;
598596
for (const key_ of Object.keys(entryOptions)) {
599-
if (
600-
key_ === "name" ||
601-
key_ === "__proto__" ||
602-
key_ === "constructor" ||
603-
key_ === "prototype"
604-
) {
605-
continue;
606-
}
607597
const key =
608598
/** @type {keyof EntryOptions} */
609599
(key_);
600+
if (key === "name") continue;
610601
if (entryOptions[key] === undefined) continue;
611602
if (existingOptions[key] !== undefined) continue;
612603
/** @type {EntryOptions[keyof EntryOptions]} */

lib/dependencies/WorkerPlugin.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,24 @@ class WorkerPlugin {
349349
)
350350
);
351351
} else {
352-
Object.assign(
353-
entryOptions,
354-
importOptions.webpackEntryOptions
355-
);
352+
// `webpackEntryOptions` is user input from a magic
353+
// comment, so copy only safe own keys to avoid
354+
// prototype pollution via `__proto__`/`constructor`/
355+
// `prototype`.
356+
const userEntryOptions = importOptions.webpackEntryOptions;
357+
for (const key of Object.keys(userEntryOptions)) {
358+
if (
359+
key === "__proto__" ||
360+
key === "constructor" ||
361+
key === "prototype"
362+
) {
363+
continue;
364+
}
365+
/** @type {EXPECTED_ANY} */
366+
(entryOptions)[key] = /** @type {EXPECTED_ANY} */ (
367+
userEntryOptions
368+
)[key];
369+
}
356370
}
357371
}
358372
if (importOptions.webpackChunkName !== undefined) {

0 commit comments

Comments
 (0)