Skip to content

fix(shared): wrap addObjectToProperties in try-catch to handle cross-origin SecurityError#36451

Open
sleitor wants to merge 1 commit into
facebook:mainfrom
sleitor:fix-36430
Open

fix(shared): wrap addObjectToProperties in try-catch to handle cross-origin SecurityError#36451
sleitor wants to merge 1 commit into
facebook:mainfrom
sleitor:fix-36430

Conversation

@sleitor
Copy link
Copy Markdown
Contributor

@sleitor sleitor commented May 11, 2026

Summary

In React 19.2 DEV builds, logComponentRender (called from commitPassiveMountOnFiber) calls addObjectToProperties which performs an unguarded for...in over every prop value. When a component receives a cross-origin Window object (e.g. iframe.contentWindow with srcdoc="" / null origin) as a prop, the enumeration throws SecurityError in browsers that enforce the same-origin policy.

This SecurityError propagates out of the commit phase and leaves the work-in-progress fiber broken, causing all subsequent renders to throw Should not already be working. and making the UI completely unresponsive.

Root Cause

addObjectToProperties in packages/shared/ReactPerformanceTrackProperties.js runs for (const key in object) without any error guard. For a cross-origin Window (null origin iframe), browsers block property enumeration and throw SecurityError. Since this error is not caught, it escapes the commit phase and corrupts the fiber tree.

Similarly, readReactElementTypeof accesses '2796107typeof' in value without a guard, which can also throw for cross-origin objects.

Fix

  • Wrap the for...in loop in addObjectToProperties with try-catch. On SecurityError, show [CrossOriginObject] as a placeholder so the render-logger degrades gracefully without corrupting the fiber.
  • Wrap the in / hasOwnProperty checks in readReactElementTypeof with try-catch so $$typeof access never escapes either.

Both are DEV-only diagnostic paths and must not affect production builds or corrupt fiber state when iterating untrusted props.

Test

Added a new test in ReactPerformanceTrack-test.js that simulates a cross-origin Window via a Proxy whose ownKeys and getOwnPropertyDescriptor traps throw, verifying that:

  1. The render completes without throwing
  2. Subsequent renders succeed (fiber tree not corrupted)

Fixes #36430

@meta-cla meta-cla Bot added the CLA Signed label May 11, 2026
@react-sizebot
Copy link
Copy Markdown

react-sizebot commented May 11, 2026

Comparing: d5736f0...71fb629

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.84 kB 6.84 kB = 1.88 kB 1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 613.53 kB 613.53 kB = 108.44 kB 108.44 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.84 kB 6.84 kB = 1.88 kB 1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 679.46 kB 679.46 kB = 119.40 kB 119.40 kB
facebook-www/ReactDOM-prod.classic.js = 699.88 kB 699.88 kB = 122.96 kB 122.96 kB
facebook-www/ReactDOM-prod.modern.js = 690.20 kB 690.20 kB = 121.35 kB 121.35 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-client/cjs/react-client-flight.development.js +0.41% 182.58 kB 183.33 kB +0.25% 31.67 kB 31.75 kB
oss-stable/react-client/cjs/react-client-flight.development.js +0.41% 182.61 kB 183.36 kB +0.25% 31.69 kB 31.77 kB
oss-experimental/react-client/cjs/react-client-flight.development.js +0.41% 182.61 kB 183.36 kB +0.25% 31.69 kB 31.77 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.40% 188.33 kB 189.08 kB +0.25% 33.01 kB 33.10 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.40% 188.38 kB 189.13 kB +0.25% 33.04 kB 33.12 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.40% 188.39 kB 189.14 kB +0.25% 33.04 kB 33.13 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.40% 188.94 kB 189.68 kB +0.20% 33.40 kB 33.47 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.40% 188.94 kB 189.68 kB +0.20% 33.40 kB 33.47 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.40% 188.94 kB 189.68 kB +0.20% 33.40 kB 33.47 kB
facebook-www/ReactFlightClient-dev.modern.js +0.39% 189.48 kB 190.23 kB +0.24% 33.45 kB 33.52 kB
facebook-www/ReactFlightClient-dev.classic.js +0.39% 189.49 kB 190.23 kB +0.24% 33.45 kB 33.52 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.39% 190.36 kB 191.11 kB +0.22% 33.43 kB 33.50 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.39% 190.41 kB 191.16 kB +0.22% 33.46 kB 33.53 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.39% 190.42 kB 191.17 kB +0.23% 33.46 kB 33.54 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.39% 192.28 kB 193.03 kB +0.20% 33.93 kB 34.00 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.39% 192.28 kB 193.03 kB +0.20% 33.93 kB 34.00 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.39% 192.28 kB 193.03 kB +0.20% 33.93 kB 34.00 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.39% 192.31 kB 193.05 kB +0.22% 33.94 kB 34.02 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.39% 192.31 kB 193.05 kB +0.22% 33.94 kB 34.02 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.39% 192.31 kB 193.05 kB +0.22% 33.94 kB 34.02 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.39% 192.93 kB 193.67 kB +0.24% 33.90 kB 33.99 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.39% 192.98 kB 193.72 kB +0.24% 33.93 kB 34.01 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.39% 192.99 kB 193.74 kB +0.24% 33.93 kB 34.02 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.39% 193.55 kB 194.30 kB +0.26% 34.08 kB 34.17 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.39% 193.60 kB 194.35 kB +0.25% 34.11 kB 34.19 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.39% 193.61 kB 194.36 kB +0.25% 34.11 kB 34.20 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.39% 193.73 kB 194.47 kB +0.22% 34.11 kB 34.18 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.39% 193.73 kB 194.47 kB +0.22% 34.11 kB 34.18 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.39% 193.73 kB 194.47 kB +0.22% 34.11 kB 34.18 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.38% 195.73 kB 196.48 kB +0.20% 34.23 kB 34.30 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.38% 195.73 kB 196.48 kB +0.20% 34.23 kB 34.30 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.38% 195.73 kB 196.48 kB +0.20% 34.23 kB 34.30 kB
oss-experimental/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js +0.38% 197.38 kB 198.13 kB +0.21% 34.47 kB 34.55 kB
oss-stable-semver/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js +0.38% 197.38 kB 198.13 kB +0.21% 34.47 kB 34.55 kB
oss-stable/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js +0.38% 197.38 kB 198.13 kB +0.21% 34.47 kB 34.55 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.38% 198.78 kB 199.53 kB +0.21% 34.74 kB 34.81 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.38% 198.78 kB 199.53 kB +0.21% 34.74 kB 34.81 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.38% 198.78 kB 199.53 kB +0.21% 34.74 kB 34.81 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.38% 198.80 kB 199.55 kB +0.20% 34.76 kB 34.83 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.38% 198.80 kB 199.55 kB +0.20% 34.76 kB 34.83 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.38% 198.80 kB 199.55 kB +0.20% 34.76 kB 34.83 kB
oss-stable-semver/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.25% 238.87 kB 239.48 kB +0.30% 53.17 kB 53.32 kB
oss-stable/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.25% 238.90 kB 239.50 kB +0.30% 53.19 kB 53.35 kB
oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.development.js +0.25% 238.90 kB 239.51 kB +0.30% 53.20 kB 53.35 kB

Generated by 🚫 dangerJS against 71fb629

@sleitor
Copy link
Copy Markdown
Contributor Author

sleitor commented May 11, 2026

Fixed the CI failure (yarn test -r=experimental --env=production).

Root cause: The original test used expect(true).toBe(true) — a no-op that passes in any environment. In production mode (__DEV__ === false), React never calls performance.measure, so performanceMeasureCalls stays empty and the assertion still passed. That tripped the gate framework: "Gated test was expected to fail, but it passed."

Fix (this force-push):

  • Assert the first render records a 'Mount' measure — proves no fiber corruption
  • Pass a fresh crossOriginWin2 on the second render (different reference → React diffs the prop and calls addObjectToProperties)
  • Assert '\u200bApp' measure is recorded and its properties contain a [CrossOriginObject] entry

In production, performance.measure is never called → performanceMeasureCalls stays empty → toHaveLength(1) fails → gate fires correctly ✅

…origin SecurityError

In React 19.2 DEV builds, logComponentRender (called from
commitPassiveMountOnFiber) calls addObjectToProperties which performs
an unguarded 'for...in' over every prop value. When a component
receives a cross-origin Window object (e.g. iframe.contentWindow with
srcdoc='' / null origin) as a prop, the enumeration throws
SecurityError in browsers that enforce the same-origin policy.

This SecurityError propagates out of the commit phase and leaves the
work-in-progress fiber broken, causing all subsequent renders to
throw 'Should not already be working.' and making the UI completely
unresponsive.

Fix:
- Wrap the 'for...in' loop in addObjectToProperties with try-catch.
  On SecurityError, show '[CrossOriginObject]' as a placeholder so
  the render-logger degrades gracefully without corrupting the fiber.
- Wrap the 'in' / hasOwnProperty checks in readReactElementTypeof
  with try-catch so 2795888typeof access never escapes either.

Both are DEV-only diagnostic paths and must not affect production
builds or corrupt fiber state when iterating untrusted props.

Repro: pass iframe.contentWindow (srcdoc iframe, null origin) as a
prop to any component in a DEV Vite+React 19.2 app.

Fixes facebook#36430
@maxtell5
Copy link
Copy Markdown

Recent Activity Summary

The React repository has seen active contributions focused on stability and developer experience. Recent pull requests address cross-origin security errors in DEV builds, infinite loop detection in production useEffect hooks, and documentation consistency. These efforts demonstrate the community's commitment to improving React's robustness across both development and production environments.

@maxtell5
Copy link
Copy Markdown

Recent Activity Summary

The facebook/react repository has been actively addressing critical bugs and documentation improvements. Recent contributions include fixes for cross-origin SecurityError handling in DEV builds, infinite loop detection in production useEffect hooks, and standardization of contribution guide URLs. All three recent PRs focus on improving developer experience and production reliability.

@maxtell5
Copy link
Copy Markdown

Recent Activity Summary

The facebook/react repository shows active development with recent contributions focused on bug fixes and documentation improvements. The most recent pull requests address critical issues including cross-origin SecurityError handling in DEV builds (#36451), infinite loop detection in production builds (#36443), and documentation URL standardization (#36445). Community contributors are actively working on improving both the stability of React's internal mechanisms and the quality of its documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: [19.2] DEV-build logComponentRender throws SecurityError on cross-origin Window props

3 participants