Skip to content

fix(server): mergeProps silently drops keys that shadow Object.prototype methods#2800

Open
JSap0914 wants to merge 1 commit into
solidjs:mainfrom
JSap0914:fix/server-mergeprops-prototype-shadow
Open

fix(server): mergeProps silently drops keys that shadow Object.prototype methods#2800
JSap0914 wants to merge 1 commit into
solidjs:mainfrom
JSap0914:fix/server-mergeprops-prototype-shadow

Conversation

@JSap0914

Copy link
Copy Markdown

Summary

The server-side mergeProps in src/server/rendering.ts used:

if (key in target) continue;

to skip keys already added to the result object. Because in walks the prototype chain, every property inherited from Object.prototype (toString, valueOf, hasOwnProperty, etc.) is always found on the plain {} target. This means any source with one of those keys as an own property is silently ignored, and the merged result exposes the inherited Object.prototype method instead of the supplied value.

The client-side implementation (src/render/component.ts) does not have this bug because it iterates source keys explicitly and only skips "__proto__" and "constructor".

Before:

// SSR context
import { mergeProps } from 'solid-js/web'; // resolves to server build
mergeProps({ toString: 1 }).toString; // → [Function: toString]  ❌
mergeProps({ valueOf: 42 }).valueOf;   // → [Function: valueOf]   ❌

After:

mergeProps({ toString: 1 }).toString; // → 1   ✅
mergeProps({ valueOf: 42 }).valueOf;  // → 42  ✅

Fix

Replace key in target with Object.prototype.hasOwnProperty.call(target, key) so only own properties already added to the result are skipped. Add explicit early returns for '__proto__' and 'constructor' to match the client-side behavior.

How did you test this change?

  • Added 4 new tests to packages/solid/test/rendering.spec.ts that import the server rendering module directly
  • All 473 existing tests continue to pass (pnpm vitest run)

AI-assisted implementation; all logic, tests, and review are my own.

…e methods

The server-side mergeProps in src/server/rendering.ts used
  if (key in target) continue;
to skip keys already present on the result object.  Because 'in'
walks the entire prototype chain, keys such as 'toString', 'valueOf',
and 'hasOwnProperty' were always found on the bare {} target via
Object.prototype, so those source properties were silently discarded.
The merged object then exposed the inherited Object.prototype method
instead of the value supplied by the caller.

Replace the 'in' check with Object.prototype.hasOwnProperty.call(target, key)
so only own properties already added to the result trigger a skip.
Add explicit early returns for '__proto__' and 'constructor' to match
the client-side mergeProps behaviour in src/render/component.ts.

Regression tests added to packages/solid/test/rendering.spec.ts.
Copilot AI review requested due to automatic review settings June 26, 2026 07:53

Copilot AI 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.

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

@changeset-bot

changeset-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a5bcdea

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
solid-js Patch
test-integration Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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.

2 participants