Commit Graph
1 Commits
Author SHA1 Message Date
Diego Cavalcante c7e7c703b7 fix(js): expose WebIDL interfaces as non-enumerable, like a real browser
`bootstrap.js` publishes its DOM interfaces with `globalThis.Node = Node`,
which defaults to `enumerable: true`. A real browser exposes every WebIDL
interface on the global as `enumerable: false`, so the difference is a
one-liner for any script that cares:

    Object.getOwnPropertyDescriptor(window, 'Node').enumerable
    // real Chrome: false     obscura: true

It also means `Object.keys(window)` and `for...in` over the global enumerate
22 names a browser would never list.

The file already has the mechanism for this -- `_preHideInternals()`
pre-declares internal globals with `enumerable: false`, and its own comment
notes that later `globalThis.x = value` assignments only update the value and
leave the descriptor intact. This just adds the WebIDL names to that list, so
no assignment site changes.

Before: 9 of 10 sampled interfaces enumerable. After: 0 of 10, matching Chrome.

Regression: interfaces still callable (`typeof Node === 'function'`),
`instanceof Node` / `instanceof Element` hold, `querySelector` works, Hacker
News still yields 30 results under `--stealth`, snapshot builds clean.

Composes with #537 -- verified with both applied: `var Node` pages run, the
JSF/RichFaces case loads (jQuery/A4J/RichFaces all live), and enumerability
stays at 0/10.
2026-08-02 01:26:42 -03:00