Commit Graph

15363 Commits

Author SHA1 Message Date
Kai Guo 3a48abc15c fix(core): preserve leave animation for sibling instances sharing a TNode
`animate.leave` was skipped — the element was removed from the DOM
synchronously instead of running its leave animation — whenever a
sibling instance of the same template entered in a different DOM parent
during the same change-detection tick (e.g. an exclusive-expansion
accordion or nav where opening section B collapses section A).

`leavingNodes` is keyed by `TNode`, which is shared by every instance of
a template. When a node was inserted, `cancelLeavingNodes` force-removed
any tracked leaving node whose DOM parent differed from the entering
node's parent (the `leavingParent !== newParent` branch added to
de-duplicate a dynamic component re-rendered into a fresh overlay pane).
For two distinct live sibling instances that merely share a `TNode`,
"different parent" is the normal situation, so the still-animating
sibling was ripped out.

Track the declaration view of each leaving element alongside it, and
only perform the cross-parent removal when the entering element belongs
to the same declaration view as the leaving one — i.e. the same logical
view re-rendered, the case the branch was written for. Two distinct
instances of a shared template have different declaration views, so
their `animate.leave` is now left to run to completion.

This preserves the dynamic-component/overlay de-duplication (#67032) and
the drag-and-drop node-move rescue (#67361), which are unchanged.

Fixes #69291

(cherry picked from commit 6b5616b2c7)
2026-06-11 17:39:01 +00:00
Hexix23 6867f77ec7 fix(http): distinguish repeated transfer cache params
Serialize transfer cache request parameters without comma-joining repeated values so distinct HttpClient requests cannot reuse the same cached response.

(cherry picked from commit a6c7fc5c13)
2026-06-11 16:59:31 +00:00
SkyZeroZx 6c1f3e9d49 fix(common): skip transfer cache for uncacheable HTTP traffic (#69316)
Do not store HTTP transfer cache entries when either the request or response
uses `Cache-Control: no-store`, `Cache-Control: private`, or
`Cache-Control: no-cache`.

Also skip transfer cache when requests use the Fetch API `cache` option with
`no-store` or `no-cache`.

Because transfer cache serializes SSR HTTP responses into the rendered HTML,
Angular now treats these directives conservatively to avoid exposing sensitive
or explicitly uncacheable data through `TransferState`.

PR Close #69316
2026-06-11 16:58:24 +00:00
SkyZeroZx 7ef1399068 fix(http): skip transfer cache for fetch credentialed requests (#69316)
Treat HttpClient requests using `credentials: 'include'` and `same-origin` as credentialed
when deciding whether a response can be stored in the HTTP transfer cache.

The transfer cache already skips requests with `withCredentials`, `Cookie`,
`Authorization`, or `Proxy-Authorization` because those responses may contain
user-specific data. Fetch-backed requests can express the same credentialed
behavior through the `credentials` option, so these responses must not be
serialized into the SSR HTML.

This keeps credentialed SSR responses out of TransferState and aligns the
cache eligibility check with the fetch request options supported by HttpClient.

PR Close #69316
2026-06-11 16:58:24 +00:00
arturovt 21bdff55da fix(zone.js): harden zoneSymbolEventNames against __proto__ key (defense-in-depth)
Initialize zoneSymbolEventNames with Object.create(null) instead of {}.

This is hardening only. addEventListener('__proto__', fn) is not
directly attacker-controllable — its presence in an application is
itself an application bug and a prerequisite for any issue here.

Without this change, if that application bug exists, two unexpected
behaviors follow depending on environment:

Browser: zoneSymbolEventNames['__proto__'] reads the __proto__ getter
and returns Object.prototype (truthy), bypassing prepareEventNames.
symbolEventName resolves to undefined and window['undefined'] = []
throws TypeError.

Node.js + --disable-proto=throw: the assignment
zoneSymbolEventNames['__proto__'] = {} inside prepareEventNames
triggers the disabled __proto__ setter and throws.

Using Object.create(null) removes the __proto__ accessor from the
map so the key is treated as a plain missing property in both cases.

(cherry picked from commit fd7c2daf4d)
2026-06-11 16:41:12 +00:00
rootvector2 94ea403563 fix(common): escape anchor fragment in shadow DOM name selector
`findAnchorFromDocument` interpolates the raw url fragment into
`[name="${target}"]` for the shadow DOM lookup, so a fragment reachable
through the router when `anchorScrolling` is on can break out of the
attribute selector and make `querySelector` throw or match unrelated
nodes, and it also breaks legitimate anchor names containing a quote.
Wrap the value in `CSS.escape` so it stays a single attribute-value token.

(cherry picked from commit a69e56df71)
2026-06-11 16:37:32 +00:00
Angular Robot cbcf31bfa9 build: update cross-repo angular dependencies
See associated pull request for more information.
2026-06-11 09:25:30 -07:00
Matthieu Riegler 2dd65d21e6 fix(http): pass down the reportUploadProgress and reportDownloadProgress on post/patch requests
The `addBody` function did not pass the argument correctly

fixes #69241

(cherry picked from commit c092a002e4)
2026-06-10 18:37:50 +00:00
Andrew Scott 4645850e24 refactor(compiler): Remove 80 char limit on AbstractEmitterVisitor
This limit breaks ts-ignore comments when using this for our source->source transform.
Rather than overridding it there, it's just removed here since we don't care about the limit

(cherry picked from commit 54112d9393)
2026-06-10 17:57:30 +00:00
Andrew Scott 4b0c3b8b8f refactor(core): Update registerNgModuleType to support codegen typechecking
Updates types and adds test for source->source transformation with tsc downstream

(cherry picked from commit d25d2e1524)
2026-06-10 17:53:00 +00:00
Andrew Scott 3f055435f6 refactor(forms): fix initWebMcpForm description to be required
updates from breakage in https://github.com/angular/angular/commit/c121407c0da2456543a54822941d71a75490b703

(cherry picked from commit a7e7a2cf05)
2026-06-10 17:51:20 +00:00
Doug Parker dbf64c8eb5 test(core): fix AI tools test flake
This test flakes occasionally because it is called in production when a platform is created and unregistered when a platform is destroyed. However, not all tests properly clean up their platforms, meaning we can accidentally leak platforms between tests. If this happens, we end up have an event listener created from the production code path and a second event listener from the test. When the test emits the event, both listeners respond and it causes too many responses which fails the test.

Ideally, all tests would clean up the platforms correctly, but this seems difficult to guarantee for all Angular tests and is likely to break over time. The simplest solution is just destroy any leaked platform before the test starts. It's a bit elegant, but the safest option.

(cherry picked from commit 492e3a2a1f)
2026-06-10 17:29:05 +00:00
SkyZeroZx 045bb736b3 fix(core): validate lowercase SVG animation attribute names
Normalize SVG animation attributeName lookup to also recognize lowercase attributename before allowing dynamic animation value bindings.

Add runtime and platform-server SSR regression coverage for lowercase attributename retargeting.

(cherry picked from commit e640692452)
2026-06-10 17:22:34 +00:00
Hexix23 1ee224ca30 fix(compiler): disallow i18n event attributes
Reject translated event-handler attributes so localization cannot bypass Angular event-attribute validation.

(cherry picked from commit 6c41f5ca01)
2026-06-10 17:21:38 +00:00
SkyZeroZx 1bd5a562f5 docs: deprecate XHR support for server-side rendering in HTTP docs and recommend Fetch
(cherry picked from commit 2066225244)
2026-06-10 17:20:43 +00:00
arturovt 3c2892c8df fix(common): prevent prototype pollution in formatDateTime
Replace `in` operator with `Object.hasOwn` in
formatDateTime to prevent prototype pollution attacks.

The `in` operator traverses the prototype chain, meaning a polluted
Object.prototype key could be picked up as a valid replacement value.
This is especially critical in SSR environments where a single
prototype pollution attack persists across all subsequent requests in
the shared Node.js process, potentially injecting malicious content
into every user's rendered HTML.

Using `Object.hasOwn` restricts the lookup to
own properties only, blocking prototype chain traversal.

(cherry picked from commit 1ec125276d)
2026-06-10 17:19:34 +00:00
Matthieu Riegler 11836a670a fix(forms): delay mcp reading the form model by a tick
Reading the form model on init is unsafe as it could depend on inputs (eg a required input). We need to delay the read by a tick (after the inputs are set) to ensure that values can be safely read.

fixes #69262

(cherry picked from commit 9604ecfd8b)
2026-06-10 17:14:45 +00:00
Matthieu Riegler 5946c18275 fix(compiler): sanitize href/xlink:href attributes of any element of the MathML namespace
The ensures that future, present and past (and precated) elements of that namespace get sanitized.

(cherry picked from commit 3927a5b271)
2026-06-10 17:13:53 +00:00
arturovt e51ad374ea fix(forms): remove animationstart listener on component destroy to prevent memory leak
The `watchValidity` method in `AnimationInputValidityMonitor` was registering
an anonymous arrow function via `addEventListener` with no corresponding
`removeEventListener` call.

In V8, each closure is represented as a `JSFunction` holding a strong pointer
to a heap-allocated `Context` object containing captured variables
(`VariableLocation::CONTEXT` slots, decided at parse time by
`Scope::MustAllocateInContext`). In Blink, DOM event listeners are stored in
the element's `EventTargetData::event_listener_map` as `JSEventListener`
wrappers backed by a `v8::Persistent<JSFunction>` handle — a strong cross-heap
reference that keeps the function alive as long as the element is alive.

Because the callback passed to `watchValidity` closes over the calling
component/directive (which itself holds a reference back to the element), this
produced a cross-heap reference cycle:

```
  HTMLInputElement (Blink/Oilpan)
    └── EventTargetData → JSEventListener → v8::Persistent<JSFunction>
          └── Context → callback closure
                └── component → HTMLInputElement  ← cycle
```

Neither V8's nor Blink's GC could independently break this cycle because it
crosses the V8/Oilpan heap boundary. The element was therefore never collected
after being removed from the DOM.

The fix stores the listener in a named local variable and registers its removal
via `DestroyRef.onDestroy`, tying cleanup to the lifetime of the component that
owns the element. This ensures `removeEventListener` is called with the exact
same `JSFunction` reference, causing Blink to drop the `v8::Persistent` handle
and allowing both the function and the element to become GC-eligible.

(cherry picked from commit 6cc54e5ede)
2026-06-10 16:56:20 +00:00
Kristiyan Kostadinov b1f02eb5c5 refactor(core): add internal utility
Sets up a utility function that we need for an internal project.

(cherry picked from commit 158307cd63)
2026-06-10 16:54:40 +00:00
Matthieu Riegler 85d2d100e3 fix(forms): harden FormGroup control lookups against prototype shadowing
Guard FormGroup control-map presence checks with safe own-property checks to avoid inherited/prototype collisions from reserved keys such as hasOwnProperty and toString.

This prevents:
- crashes from shadowed hasOwnProperty access paths
- incorrect early-return and existence behavior for prototype-named controls

Adds regression tests for prototype-shadowed keys covering:
- register/add with toString
- contains/get with hasOwnProperty
- setControl/removeControl with toString
- FormRecord behavior with hasOwnProperty

(cherry picked from commit f06b96d181)
2026-06-10 02:28:00 +00:00
Matthieu Riegler 6e3d51d7df refactor(migrations): Improve safeNavigationMigration heuristic
There is no need to migrate expressions with a nullish comparison.

fixes #69274

(cherry picked from commit 6b0150faad)
2026-06-10 00:11:59 +00:00
Andrew Scott 01ea640539 refactor(core): Fix DirectiveDefinition interface to allow abstract classes
Interface should permit abstract classes since directives can be abstract

(cherry picked from commit d1539a8513)
2026-06-09 23:21:08 +00:00
Jad Chahed a704b08379 docs: add Signal Forms and v22 guidance to AI best-practices and llms.txt
Update the AI codegen resources for Angular v22:
- best-practices.md: OnPush is the default in v22+ (don't set it explicitly),
  recommend Signal Forms, and recommend the @Service decorator.
- llms.txt: add a Signal Forms reference, the httpResource guide, and an
  Accessibility section linking the Angular Aria overview.

(cherry picked from commit 248e9c146d)
2026-06-09 21:00:00 +00:00
Andrew Scott 43a0e28729 fix(language-service): prevent external template inlay hints from appearing in TS files
Inlay hints from external templates were being incorrectly applied to
TypeScript files because the compiler was processing all templates
associated with components found in the TS file, regardless of whether
the template was inline or external. This resulted in misplaced hints
due to mismatched offsets.

This change filters the templates and host bindings processed in
getInlayHintsForTemplate to only include those that belong to the
target file being queried.

Fixes #69224

(cherry picked from commit 2e4ed8027d)
2026-06-09 20:33:19 +00:00
Kristiyan Kostadinov 4289c4c840 fix(core): update comment for Default change detection
Updates the comment on `ChangeDetectionStrategy.Default` to mention that it's the same as `Eager`.

Fixes #69253.

(cherry picked from commit 5829177729)
2026-06-09 20:10:04 +00:00
Andrew Scott 562a566ead fix(core): Handle synchronous errors in PendingTasks.run function
catches synchronous errors coming out of the function passed to PendingTasks.run

(cherry picked from commit 0e16bb701f)
2026-06-09 19:24:26 +00:00
Andrew Scott 43edc8410f fix(router): use native URL object for navigation boundary and comparison
Previously, `NavigationStateManager` relied on string-based comparisons and `.substring()` to match `NavigateEvent` URLs against internal router transitions or the application root boundary. This was brittle against trailing slashes, query parameter order variations, and sibling application URLs.

This commit updates the logic to:

- Use the native `URL` object to strictly compare `origin` and `pathname` for `appRootURL` boundaries.

- Sort `searchParams` and use `Location.stripTrailingSlash()` to robustly compare the router destination against the event destination.

- Pre-compute and store `appRootUrl` as a `URL` object to avoid redundant parsing on every navigation.

(cherry picked from commit fe721868a6)
2026-06-09 11:15:20 -07:00
arturovt c4b5fa3c92 fix(common): escape CSS string-terminating characters in escapeCssUrl
The `escapeCssUrl` helper used by `NgOptimizedImage` to sanitize placeholder URLs for use in the `background-image` CSS property previously escaped only backslashes and double quotes. However, several characters that can terminate a CSS quoted string according to the CSS Syntax Level 3 specification were left unescaped, allowing a crafted placeholder URL to break out of the `url("...")` context and inject arbitrary CSS.

This change additionally escapes the following characters using CSS hex escapes:

* `U+000A` (LINE FEED) → `\A `
* `U+000D` (CARRIAGE RETURN) → `\D `
* `U+000C` (FORM FEED) → `\C `
* `U+0000` (NULL) → `\0 `

For example:

```text id="1w5vkp"
x.com/img\nx.jpg  →  x.com/img\A x.jpg
x.com/img\rx.jpg  →  x.com/img\D x.jpg
x.com/img\fx.jpg  →  x.com/img\C x.jpg
x.com/img\0x.jpg  →  x.com/img\0 x.jpg
```

The trailing space is required by the CSS tokenizer to terminate the escape sequence and prevent the following character from being interpreted as part of the escape.

The backslash replacement remains first in the chain to avoid double-escaping the backslashes introduced by subsequent replacements.

(cherry picked from commit 3dd35c242c)
2026-06-09 10:40:25 -07:00
cexbrayat cdcea80327 fix(core): require WebMCP tool descriptions
The WebMCP ModelContextTool dictionary marks description as required: https://webmachinelearning.github.io/webmcp/#modelcontexttool-dictionary

(cherry picked from commit c121407c0d)
2026-06-09 10:29:15 -07:00
Matthieu Riegler f908a3e6bf refactor(core): harden change store access
This prevents any attack through prototype polution.

(cherry picked from commit bff084f203)
2026-06-09 17:05:58 +00:00
Alan Agius 1881ede3a7 refactor(platform-server): deprecate ServerXhr
XHR support in `@angular/platform-server` is deprecated because the underlying `xhr2` library does not safely handle redirects. Specifically, it can forward `Authorization` headers on cross-origin redirects (which leaks credentials) and is susceptible to denial-of-service (DoS) via redirect loops.

DEPRECATED: XHR support in `@angular/platform-server` is deprecated. Use standard `fetch` APIs instead.
(cherry picked from commit 8446e46f8b)
2026-06-09 16:54:21 +00:00
Matthew Beck 96b6419d95 ci: run benchmark comparison in isolated worktree and harden security
- Run comparison benchmark in an isolated git worktree to prevent workspace pollution and local branch conflicts.
- Harden security by passing benchmark target and SHA as environment variables to prevent shell injection, and adding '--' to bazel query and git rev-parse.
- Optimize workflow by removing pnpm caching to mitigate cache poisoning risks.
- Improve robustness of benchmark log parsing, supporting both ZIP outputs and raw directories, and safely checking for JSON reports.
- Centralize git command execution on the dev-infra GitClient for consistency.
- Add tslib to benchpress dependencies to prevent module resolution failures.

(cherry picked from commit 547d85addf)
2026-06-09 16:48:55 +00:00
SkyZeroZx 4254eb416c fix(http): preserve empty referrer option in HttpRequest
Preserve `referrer: ''` when constructing and cloning HttpRequest.

An empty string is a valid Fetch referrer value and is documented by
Angular as the way to omit referrer information for sensitive requests.
The previous truthy checks treated it as if the option was not provided,
causing requests to fall back to the browser default referrer behavior.

(cherry picked from commit cd771d3712)
2026-06-09 16:41:24 +00:00
SkyZeroZx cf97b1f828 fix(service-worker): Strips sensitive headers on cross-origin redirects
Removes `Authorization`, `Cookie`, and `Proxy-Authorization` headers when a request is redirected to a different origin. This aligns with the Fetch API's redirect algorithm to prevent sensitive information from being sent to third-party origins.

(cherry picked from commit 47d68dcb26)
2026-06-08 21:49:34 +00:00
SkyZeroZx 167bd4c162 fix(http): Rejects non-HTTP(S) URLs in JSONP requests
Prevents JSONP requests from using URLs with unsupported protocols for improved security.

Fixes #68832

(cherry picked from commit 231eff19a1)
2026-06-08 13:56:46 -07:00
SkyZeroZx 393b84caf8 fix(compiler): sanitize two-way properties
Apply schema-derived sanitizer resolution to TwoWayProperty ops so native two-way DOM bindings emit the same sanitizer as one-way property bindings.

Add compiler compliance coverage for innerHTML, srcdoc, URL, resource URL, and security-sensitive attribute cases.

(cherry picked from commit 3c70270c96)
2026-06-08 20:12:27 +00:00
arturovt d4e08da89d refactor(core): convert LocaleDataIndex from enum to const object
TypeScript enums compile to self-executing function expressions that
are not tree-shakable, even when unused. Replace LocaleDataIndex with
a plain const object using `as const` to produce the same numeric
indices and literal types without the IIFE side-effect.

(cherry picked from commit d3239a3ac2)
2026-06-05 18:10:47 +00:00
SkyZeroZx dfff57ede9 fix(common): Limits date format string length
Introduces a maximum length of 256 characters for date format strings.

This prevents potential Denial of Service (DoS) attacks by throwing an
`INVALID_DATE_FORMAT` error if an excessively long format string is
provided to `formatDate` or `DatePipe`, safeguarding against performance
degradation or application crashes.

(cherry picked from commit eeb03f4ea3)
2026-06-05 17:58:41 +00:00
Alan Agius ed48ca7f51 fix(platform-server): harden platform location origin validation during SSR
Add allowOriginChange option to ResolveUrlOptions in resolveUrl to enforce same-origin validation on resolved URLs. When set to false, it prevents any cross-origin changes (including HTTP/HTTPS URLs), aligning the emulated server-side platform location environment with browser security behavior.

Refactor ServerPlatformLocation.replaceState to use allowOriginChange: false instead of manual comparison, hardening state change validation against cross-origin URLs.

Add unit tests in url_spec.ts and platform_location_spec.ts for the origin validation changes.
2026-06-05 10:44:20 -07:00
Alan Agius feb040043d refactor(platform-server): replace standard Error with RuntimeError
Update platform-server to use Angular 's native `RuntimeError` class.
This aligns error throwing patterns in platform-server with other packages of the framework such as core, common, and platform-browser.

For URL and host errors, the error messages are configured to return only the raw dynamic URL when `ngDevMode` is false (in production) to aid in troubleshooting without bloating production bundles.
2026-06-05 10:44:20 -07:00
Alan Agius 1d87c49f6e fix(common): use cryptographically secure SHA-256 for transfer cache key generation
Replace the custom 64-bit non-cryptographic combined DJB2 hashing implementation in HttpTransferCache with a robust, pure JavaScript, synchronous SHA-256 algorithm.

Using DJB2 is vulnerable to pre-image and second-preimage attacks due to its small 64-bit keyspace and mathematical simplicity. An attacker could craft colliding request inputs to poison the cache, potentially causing a CDN or the application to serve the wrong cached response to legitimate users.

SHA-256 provides strong cryptographic collision resistance, preventing cache key collision attacks. A custom synchronous implementation is required because the Web Crypto API (`crypto.subtle.digest`) is asynchronous, whereas the transfer cache state lookup and interceptor flow must operate synchronously.

Also, update the unit tests to dynamically verify the custom SHA-256 output against the native Web Crypto API.
2026-06-05 10:40:20 -07:00
Doug Parker 55b7b5a6b6 fix(forms): set additionalProperties: false on generated WebMCP form
This tells the agent that all input properties have been explicitly declared and that it should not attempt to specify additional arguments with unknown names. This provides a little more safety and gives the AI a little more information about the allowed set of inputs for this tool.

(cherry picked from commit df77e42327)
2026-06-04 21:18:10 +00:00
Matthieu Riegler ffb06c0514 fix(http): ensure query parameters are inserted before URL fragments
Previously, when making an HTTP request where the URL contained a fragment (`#`) and `HttpParams` were provided, the parameters were appended to the very end of the URL (after the fragment). This resulted in the parameters being treated as part of the fragment rather than query parameters, potentially bypassing server-side logic and validation.
This commit updates the URL parsing logic in `HttpRequest` to split the URL by the fragment, correctly inserting the query string before any fragment.

(cherry picked from commit cb8ceb1dde)
2026-06-04 21:02:04 +00:00
Stewart McGown e9fc72e16b test(core): add GC-based tests for signal graph prevConsumer leak fix (#68681)
Uses WeakRef + global.gc() to verify that destroyed effect consumers
become garbage-collectable when a non-live computed reads the same
producer.

The jasmine_test target is configured with node_options: --expose-gc.
GC tests are skipped in browser targets via isBrowser from
@angular/private/testing.

Made-with: Cursor

PR Close #68681
2026-06-04 19:25:37 +00:00
Stewart McGown 29fdb98684 fix(core): prevent dangling prevConsumer reference from leaking destroyed views (#68681)
When `producerAccessed` creates a new link for a non-live consumer (e.g.
a computed signal with no readers), it eagerly sets `prevConsumer` to the
producer's current `consumersTail`. However, because the consumer is not
live, `producerAddLiveConsumer` is skipped and the link is never inserted
into the producer's consumer doubly-linked list.

This means the link holds a reference *into* the producer's consumer list
without being *part* of it. When the node that `prevConsumer` points to is
later removed via `producerRemoveLiveConsumerLink`, the dangling link is
not patched because it isn't traversable from the list.

The result is that the removed consumer link — and everything it
references — is kept alive by the dangling `prevConsumer` pointer on the
non-live link, which itself is kept alive through the computed signal's
`producers` linked list.

In practice this causes multi-MB memory leaks in Angular apps: a
root-provided service with a computed signal (e.g. `AttachmentApiService.urls`)
holds a producer link to `ApplicationEnvironmentService.environmentSignal`.
That link's `prevConsumer` captures a stale reference to a destroyed view's
`ReactiveLViewConsumer` link, retaining the entire LView hierarchy —
components, QueryLists, ElementRefs, and detached DOM — after the view is
destroyed.

The fix initializes `prevConsumer` to `undefined` at link creation time.
This is safe because `producerAddLiveConsumer` unconditionally sets
`link.prevConsumer = consumersTail` (line 513) when the link is actually
inserted into the consumer list. The value set in `producerAccessed` was
always overwritten for live consumers, and was never correct for non-live
consumers.

Made-with: Cursor

PR Close #68681
2026-06-04 19:25:37 +00:00
Doug Parker 669146b0e7 fix(core): disable WebMCP during SSR
In certain scenarios like `provideExperimentalWebMcpTools` in `app.config.ts`, a WebMCP tool may be declared before SSR has a chance to polyfill Domino and trigger an error due to an `undefined` `document` value. This aborts from the process before WebMCP has a chance to crash.

(cherry picked from commit e50d47a493)
2026-06-04 18:44:33 +00:00
arturovt 3dd433b39a fix(core): use Object.hasOwn to handle null-prototype objects in toStylingKeyValueArray
Calling `.hasOwnProperty()` on an object created with `Object.create(null)`
throws a TypeError because such objects have no prototype and therefore no
inherited `hasOwnProperty` method. Replace it with `Object.hasOwn()`, which
is a static method immune to prototype chain issues.

Adds a regression test covering null-prototype objects passed to
`toStylingKeyValueArray`.

(cherry picked from commit a786862c54)
2026-06-04 18:37:48 +00:00
Matthieu Riegler 302cb601be refactor(core): Also throw an error on iframe attributes set to undefined
This is more a hardening concern. Other non-nullish values were already throwing but here we make it explicit that undefined also throws.

(cherry picked from commit c5293c4c9d)
2026-06-04 17:00:35 +00:00
Matthieu Riegler fa546f382d fix(core): harden TransferState restoration against DOM clobbering
Reject non-script elements when reading the SSR transfer state payload by id.
This prevents attacker-controlled elements with a clobbered id from spoofing
hydration state.

(cherry picked from commit 6bde84fa8e)
2026-06-03 23:03:01 +00:00