You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(runtime): suggest --unstable-unsafe-proto after __proto__ access (#35192)
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
access 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.
Reads and writes are recorded under separate flags because they fail
differently. A write silently no-ops and the breakage surfaces
downstream at an unrelated-looking line, so any later crash is enough to show the hint. A
read instead returns `undefined` and crashes right at the access site (for
example pnpm 11's `who.__proto__.constructor`), so the hint for a read is only
shown when the crashing error itself mentions `__proto__`. That keeps programs
that merely probe `__proto__` for feature detection, and then crash for an
unrelated reason, from getting a spurious suggestion.
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.
These are the real-world `__proto__` crashes the hint now points at,
each of which runs correctly under `--unstable-unsafe-proto`:
Closes#34694Closes#34337Closes#26584Closes#24986Closes#24413Closes#35131
0 commit comments