Skip to content

fix(cli): block prototype-pollution payloads in --env parsing#14165

Merged
stormslowly merged 3 commits into
mainfrom
fix/cli-env-prototype-pollution
May 27, 2026
Merged

fix(cli): block prototype-pollution payloads in --env parsing#14165
stormslowly merged 3 commits into
mainfrom
fix/cli-env-prototype-pollution

Conversation

@stormslowly

@stormslowly stormslowly commented May 27, 2026

Copy link
Copy Markdown
Contributor

Why

Harden rspack-cli --env parsing against prototype-pollution-style key paths so that:

  • malicious dotted keys cannot mutate Object.prototype (and from there leak into every plain object created later in the build)
  • reserved RSPACK_* build flags written by the CLI can't be overridden through the prototype chain

What

packages/rspack-cli/src/utils/options.ts

  • Block dotted --env paths whose segments hit a small dangerous-key denylist (lodash _.set hardening pattern).
  • setBuiltinEnvArg now uses Object.prototype.hasOwnProperty.call instead of in, so a polluted prototype can't mask a legitimate write.

packages/rspack-cli/tests/utils/options.test.ts (new)

  • Regression coverage for the hardened parser plus the existing nested-key and plain-object-shape happy paths.

Single-package change, no public API impact — the env object passed to user config functions keeps its plain {} shape.

Credits

Reported privately via responsible disclosure by the security research team from the University of Sydney, focusing on detecting open source software vulnerabilities:

Thanks for the careful write-up and the heads-up before public disclosure.

The dotted-key parser in `normalizeEnvToObject` walked into
`Object.prototype` when a key path started with `__proto__`,
`constructor`, or `prototype`, and `setBuiltinEnvArg` used `in`
(which traverses the prototype chain) to detect an existing
reserved RSPACK_* flag — so an attacker controlling `--env`
could pollute every plain object in the process and spoof
reserved build-mode flags.

Mitigations applied to packages/rspack-cli/src/utils/options.ts:

- Reject any `--env` whose dotted path contains
  `__proto__` / `constructor` / `prototype` (aligned with lodash
  `_.set` hardening for CVE-2020-8203).
- Build the root and every intermediate node with
  `Object.create(null)` so lookups can never reach
  `Object.prototype`.
- Replace `(envName in env)` with `Object.hasOwn(env, envName)`
  in `setBuiltinEnvArg` so a polluted prototype cannot mask a
  legitimate write.

Regression coverage: packages/rspack-cli/tests/utils/options.test.ts
asserts the three payload shapes (`__proto__.X=Y`,
`constructor.prototype.X=Y`, and reserved-flag spoofing) plus
the existing nested-key happy path.
Copilot AI review requested due to automatic review settings May 27, 2026 01:53
@stormslowly stormslowly requested a review from hardfist as a code owner May 27, 2026 01:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b32ca361b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/rspack-cli/src/utils/options.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens rspack-cli’s --env dotted-key parsing against prototype-pollution payloads to prevent Object.prototype mutation and reserved RSPACK_* flag spoofing during normalizeCommonOptions.

Changes:

  • Prevents dangerous path segments (__proto__, constructor, prototype) from being applied during --env parsing.
  • Uses Object.create(null) for env roots/intermediates to avoid prototype-chain lookups.
  • Adds unit tests covering both nested-key parsing and prototype-pollution payload shapes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/rspack-cli/src/utils/options.ts Adds prototype-pollution hardening to --env parsing and reserved-flag writes.
packages/rspack-cli/tests/utils/options.test.ts Adds tests to verify nested env parsing and protection against prototype-pollution payloads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/rspack-cli/src/utils/options.ts Outdated
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing aa06865 to fix: require swc helpers 0.5.22 (#14160) by Fy

🙈 Size remains the same at 61.82MB

@codspeed-hq

codspeed-hq Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 37 untouched benchmarks
⏩ 25 skipped benchmarks1


Comparing fix/cli-env-prototype-pollution (aa06865) with main (9d35e6e)2

Open in CodSpeed

Footnotes

  1. 25 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (6471d07) during the generation of this report, so 9d35e6e was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Address PR #14165 review feedback:

- Codex (P2): the env object is handed to the user's rspack config
  function `(env) => ({...})`, so changing it to a null-prototype
  object breaks benign callsites that do `env.hasOwnProperty(...)`
  or `env instanceof Object`. The dangerous-key denylist already
  fences off pollution at the parser entrance, so the root and
  intermediate nodes can stay as plain `{}` without losing the
  security property.

- Copilot: `Object.hasOwn` requires ES2022 but the repo targets
  ES2021. Switch to `Object.prototype.hasOwnProperty.call`, which
  has the same no-prototype-lookup guarantee.

Add a regression test asserting `env instanceof Object` and
`env.hasOwnProperty(...)` continue to work for benign inputs.
@stormslowly

Copy link
Copy Markdown
Contributor Author

Addressed both review comments in 3b44f09:

  • Codex (P2): reverted root + intermediate nodes to plain {}. The dangerous-key denylist already fences off pollution at the parser entrance, so the env object handed to user config functions keeps its expected shape (env.hasOwnProperty(...), env instanceof Object).
  • Copilot: swapped Object.hasOwn for Object.prototype.hasOwnProperty.call to stay within the repo's ES2021 target.

Added a regression test asserting the plain-object shape for benign inputs. All 6 unit tests green locally.

@stormslowly stormslowly requested a review from chenjiahan May 27, 2026 02:28
@stormslowly stormslowly enabled auto-merge (squash) May 27, 2026 02:29
@github-actions

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 5 projects in monorepo, 5 projects with changes.

📊 Quick Summary
Project Total Size Change
popular-libs 1.7 MB -
react-10k 5.7 MB -
react-1k 826.4 KB -
react-5k 2.7 MB -
ui-components 4.8 MB -
📋 Detailed Reports (Click to expand)

📁 popular-libs

Path: ../build-tools-performance/cases/popular-libs/dist/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 1.7 MB - -
📄 JavaScript 1.7 MB - -
🎨 CSS 0 B - -
🌐 HTML 289.0 B - -
📁 Other Assets 0 B - -

📁 react-10k

Path: ../build-tools-performance/cases/react-10k/dist/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 5.7 MB - -
📄 JavaScript 5.7 MB - -
🎨 CSS 21.0 B - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

📁 react-1k

Path: ../build-tools-performance/cases/react-1k/dist/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 826.4 KB - -
📄 JavaScript 826.0 KB - -
🎨 CSS 0 B - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

📁 react-5k

Path: ../build-tools-performance/cases/react-5k/dist/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 2.7 MB - -
📄 JavaScript 2.7 MB - -
🎨 CSS 21.0 B - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

📁 ui-components

Path: ../build-tools-performance/cases/ui-components/dist/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 4.8 MB - -
📄 JavaScript 4.7 MB - -
🎨 CSS 107.0 KB - -
🌐 HTML 328.0 B - -
📁 Other Assets 0 B - -

Generated by Rsdoctor GitHub Action

@stormslowly stormslowly merged commit d05392f into main May 27, 2026
36 checks passed
@stormslowly stormslowly deleted the fix/cli-env-prototype-pollution branch May 27, 2026 03:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants