Skip to content

fix(unset): guard against prototype keyword path traversal - #13560

Merged
bluebill1049 merged 1 commit into
react-hook-form:masterfrom
JSap0914:fix/unset-prototype-keywords-guard
Jun 30, 2026
Merged

fix(unset): guard against prototype keyword path traversal#13560
bluebill1049 merged 1 commit into
react-hook-form:masterfrom
JSap0914:fix/unset-prototype-keywords-guard

Conversation

@JSap0914

Copy link
Copy Markdown
Contributor

Summary

unset() in src/utils/unset.ts traverses path segments through baseGet() without checking for prototype-pollution keywords (__proto__, constructor, prototype). This allows callers to inadvertently (or maliciously) delete properties from Object.prototype.

set.ts already contains an equivalent guard:

if (PROTOTYPE_KEYWORDS.includes(key)) {
  return;
}

but unset.ts was never updated to match.

Bug

import unset from "./src/utils/unset";

// Prototype extended by some library / JSON merge vulnerability
Object.prototype.polluted = "SENSITIVE";

unset({}, "__proto__.polluted");

console.log({}.polluted); // undefined — deleted from Object.prototype!

The same issue occurs with array-form paths (["__proto__", "polluted"]) and the constructor / prototype keywords.

Fix

After computing the paths array in unset(), bail out immediately (no-op) if any segment is in PROTOTYPE_KEYWORDS, mirroring the guard in set.ts.

Verification

New test added to src/__tests__/utils/unset.test.ts:

  • RED (before fix): test fails — unset({}, "__proto__.foo") deleted from Object.prototype.
  • GREEN (after fix): 19/19 tests pass, including the new prototype-guard test.
Tests: 19 passed, 19 total

Full utils suite still green: 134/134 tests pass.

Closes #13559

…k-form#13559)

The unset() utility traverses nested paths via an internal baseGet()
helper without checking for prototype-pollution keywords (__proto__,
constructor, prototype).  set.ts already contains this guard, but
unset.ts did not have an equivalent.

As a result, a path like '__proto__.foo' would cause baseGet to walk
into Object.prototype, and the subsequent delete would remove a
property from the prototype itself.

Fix: after computing the paths array, bail out early (no-op) if any
segment is in PROTOTYPE_KEYWORDS, matching the existing protection in
set.ts.

Fixes react-hook-form#13559
Copilot AI review requested due to automatic review settings June 29, 2026 08:40

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@bluebill1049
bluebill1049 merged commit a00a1e3 into react-hook-form:master Jun 30, 2026
6 checks passed
KATT added a commit to KATT/react-hook-form that referenced this pull request Jul 3, 2026
…bmitting-cypress-jest

* origin/master:
  🐞 fix(flatten): preserve Date values as leaf nodes (react-hook-form#13566)
  Revert "docs: fix grammar in demo descriptions (react-hook-form#13565)" (react-hook-form#13568)
  Revert "test: remove duplicate UseFieldArray slug (react-hook-form#13564)" (react-hook-form#13567)
  test: remove duplicate UseFieldArray slug (react-hook-form#13564)
  docs: fix grammar in demo descriptions (react-hook-form#13565)
  🐞 fix(useController): reflect cleared parent object in controlled fields (react-hook-form#13550) (react-hook-form#13553)
  📖 docs: replace dead /api links with /docs in locale READMEs (react-hook-form#13561)
  🐛 fix(unset): guard against prototype keyword path traversal (react-hook-form#13559) (react-hook-form#13560)
  📖 docs: replace retired /jp, /pt, /zh subdomain links in locale READMEs (react-hook-form#13556)
KATT added a commit to KATT/react-hook-form that referenced this pull request Jul 3, 2026
…ssubmitting

* repro/activity-issubmitting-vitest:
  🐞 fix(flatten): preserve Date values as leaf nodes (react-hook-form#13566)
  Revert "docs: fix grammar in demo descriptions (react-hook-form#13565)" (react-hook-form#13568)
  Revert "test: remove duplicate UseFieldArray slug (react-hook-form#13564)" (react-hook-form#13567)
  test: remove duplicate UseFieldArray slug (react-hook-form#13564)
  docs: fix grammar in demo descriptions (react-hook-form#13565)
  🐞 fix(useController): reflect cleared parent object in controlled fields (react-hook-form#13550) (react-hook-form#13553)
  📖 docs: replace dead /api links with /docs in locale READMEs (react-hook-form#13561)
  🐛 fix(unset): guard against prototype keyword path traversal (react-hook-form#13559) (react-hook-form#13560)
  📖 docs: replace retired /jp, /pt, /zh subdomain links in locale READMEs (react-hook-form#13556)
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.

bug: unset() can delete from Object.prototype via __proto__ path traversal (missing PROTOTYPE_KEYWORDS guard)

3 participants