Skip to content

Commit 1abc864

Browse files
committed
Add trusted-prevent-dom-bypass scriptlet
@description Prevent the bypassing of uBO scriptlets through anonymous embedded context. To ensure that a target method in the embedded context is using the corresponding parent context's method (which is assumed to be properly patched), or to replace the embedded context with that of the parent context. Root issue: https://issues.chromium.org/issues/40202434 @param methodPath The method which calls must be intercepted. The arguments of the intercepted calls are assumed to be HTMLElement, anything else will be ignored. @param selector (optional) A plain CSS selector which will be used in a `document.querySelector()` call, to validate that the returned element must be processed by the scriptlet. If no selector is provided, all elements will be processed. @param targetMethod (optional) The method in the embedded context which should be delegated to the parent context. If no method is specified, the embedded context becomes the parent one, i.e. all properties of the embedded context will be that of the parent context.
1 parent 5133991 commit 1abc864

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

assets/resources/scriptlets.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5143,4 +5143,79 @@ function trustedPreventXhr(...args) {
51435143
return preventXhrFn(true, ...args);
51445144
}
51455145

5146+
/**
5147+
*
5148+
* @trustedScriptlet trusted-prevent-dom-bypass
5149+
*
5150+
* @description
5151+
* Prevent the bypassing of uBO scriptlets through anonymous embedded context.
5152+
*
5153+
* Ensure that a target method in the embedded context is using the
5154+
* corresponding parent context's method (which is assumed to be
5155+
* properly patched), or to replace the embedded context with that of the
5156+
* parent context.
5157+
*
5158+
* Root issue:
5159+
* https://issues.chromium.org/issues/40202434
5160+
*
5161+
* @param methodPath
5162+
* The method which calls must be intercepted. The arguments
5163+
* of the intercepted calls are assumed to be HTMLElement, anything else will
5164+
* be ignored.
5165+
*
5166+
* @param selector (optional)
5167+
* A plain CSS selector which will be used in a `document.querySelector()`
5168+
* call, to validate that the returned element must be processed by the
5169+
* scriptlet. If no selector is provided, all elements will be processed.
5170+
*
5171+
* @param targetMethod (optional)
5172+
* The method in the embedded context which should be delegated to the
5173+
* parent context. If no method is specified, the embedded context becomes
5174+
* the parent one, i.e. all properties of the embedded context will be that
5175+
* of the parent context.
5176+
*
5177+
* */
5178+
5179+
builtinScriptlets.push({
5180+
name: 'trusted-prevent-dom-bypass.js',
5181+
requiresTrust: true,
5182+
fn: trustedPreventDomBypass,
5183+
dependencies: [
5184+
'proxy-apply.fn',
5185+
'safe-self.fn',
5186+
],
5187+
});
5188+
function trustedPreventDomBypass(
5189+
methodPath = '',
5190+
selector = '',
5191+
targetMethod = ''
5192+
) {
5193+
if ( methodPath === '' ) { return; }
5194+
const safe = safeSelf();
5195+
const logPrefix = safe.makeLogPrefix('trusted-prevent-dom-bypass', methodPath, selector, targetMethod);
5196+
proxyApplyFn(methodPath, function(context) {
5197+
const elems = context.callArgs.filter(e => e instanceof HTMLElement);
5198+
const r = context.reflect();
5199+
if ( elems.length === 0 ) { return r; }
5200+
const targetContexts = selector !== ''
5201+
? new Set(document.querySelectorAll(selector))
5202+
: undefined;
5203+
for ( const elem of elems ) {
5204+
try {
5205+
if ( `${elem.contentWindow}` !== '[object Window]' ) { continue; }
5206+
if ( elem.contentWindow.location.href !== 'about:blank' ) { continue; }
5207+
if ( targetContexts && targetContexts.has(elem) === false ) { continue; }
5208+
if ( targetMethod !== '' ) {
5209+
elem.contentWindow[targetMethod] = self[targetMethod];
5210+
} else {
5211+
Object.defineProperty(elem, 'contentWindow', { value: self });
5212+
}
5213+
safe.uboLog(logPrefix, 'Bypass prevented');
5214+
} catch(_) {
5215+
}
5216+
}
5217+
return r;
5218+
});
5219+
}
5220+
51465221
/******************************************************************************/

0 commit comments

Comments
 (0)