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.
This commit is contained in:
1 parent
eab2a5eea1
commit
c7e7c703b7
1 file changed
+12
Vendored
+12
@@ -36,6 +36,18 @@
|
|||||||
'_rngAncestors', '_rngOrder', '_rngCmp', '_rngCheckOffset',
|
'_rngAncestors', '_rngOrder', '_rngCmp', '_rngCheckOffset',
|
||||||
'_idbRequest', '_idbObjectStore', '_idbTransaction', '_idbDatabase',
|
'_idbRequest', '_idbObjectStore', '_idbTransaction', '_idbDatabase',
|
||||||
'_makeListenerBox',
|
'_makeListenerBox',
|
||||||
|
// WebIDL interfaces. A real browser exposes these on the global as
|
||||||
|
// enumerable:false; here they were assigned with `globalThis.X = X`, which
|
||||||
|
// defaults to enumerable:true and is detectable in one line:
|
||||||
|
// Object.getOwnPropertyDescriptor(window, 'Node').enumerable
|
||||||
|
// Pre-declaring them non-enumerable here is enough -- per the note above,
|
||||||
|
// the later `globalThis.X = X` assignments only update the value.
|
||||||
|
'Node', 'Element', 'Document', 'DocumentFragment', 'DocumentType',
|
||||||
|
'Text', 'Comment', 'CDATASection', 'ProcessingInstruction', 'CharacterData',
|
||||||
|
'CSSStyleDeclaration', 'DOMTokenList', 'Screen', 'NetworkInformation',
|
||||||
|
'MessageChannel', 'MessagePort', 'CustomElementRegistry',
|
||||||
|
'XMLHttpRequestEventTarget', 'HTMLMediaElement', 'HTMLVideoElement',
|
||||||
|
'HTMLAudioElement', 'WebGL2RenderingContext',
|
||||||
];
|
];
|
||||||
var _desc = { value: undefined, writable: true, enumerable: false, configurable: true };
|
var _desc = { value: undefined, writable: true, enumerable: false, configurable: true };
|
||||||
for (var _i = 0; _i < _names.length; _i++) {
|
for (var _i = 0; _i < _names.length; _i++) {
|
||||||
|
|||||||
Reference in new issue
Block a user