Skip to content

fix(runtime): suggest --unstable-unsafe-proto after __proto__ assignment#35192

Open
bartlomieju wants to merge 3 commits into
mainfrom
feat/proto-set-suggestion
Open

fix(runtime): suggest --unstable-unsafe-proto after __proto__ assignment#35192
bartlomieju wants to merge 3 commits into
mainfrom
feat/proto-set-suggestion

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

Deno disables the Object.prototype.__proto__ accessor by default to guard
against prototype pollution. It did this by deleting the property, so reads
return undefined and writes silently create a useless own property without
changing the prototype. These quiet failures are hard to track down when code
accidentally relies on __proto__.

Making the accessor throw instead (#34730) surfaced those bugs but broke real
packages such as Playwright, and was reverted (#34772). This takes a middle
ground: it keeps the silent behavior, but installs an accessor that reproduces
the deleted semantics exactly (read returns undefined, write creates an own
data property, the prototype is unchanged) while recording the first
assignment in a process-global flag. When the program later crashes, the
uncaught-error formatter appends a hint to run again with
--unstable-unsafe-proto. Programs that never touch __proto__, and runs with
the flag already enabled, are unaffected.

One consequence is that the accessor is now present in both modes (which
matches Node, where it always exists), so Object.hasOwn(Object.prototype, "__proto__") is now true by default rather than false. The detection in
the existing tests and the unsafe-proto fixture therefore switches from
checking presence to checking behavior: reading __proto__ returns undefined
only when the accessor is disabled.

Deno disables the `Object.prototype.__proto__` accessor by default to guard
against prototype pollution. It did this by deleting the property, so writes
silently created a useless own property and reads returned `undefined`, which
makes accidental reliance on `__proto__` hard to debug.

Making the accessor throw instead (#34730) surfaced those bugs but broke real
packages such as Playwright and was reverted (#34772). This keeps the silent
behavior but installs an accessor that reproduces the deleted semantics exactly
(read -> `undefined`, write -> own data property, prototype unchanged) while
recording the first assignment. When the program then crashes, the
uncaught-error formatter appends a hint to run again with
`--unstable-unsafe-proto`.

The accessor is now present in both modes (matching Node), so the unsafe-proto
detection in the tests and fixtures switches from checking presence to checking
behavior (reading `__proto__` returns `undefined` only when disabled).
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.

1 participant