From a38b1af97f24e8ef6746fdec42c92648ba695856 Mon Sep 17 00:00:00 2001 From: Kuitos Date: Thu, 2 Nov 2023 21:13:16 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20createElement=20hijack=20must=20?= =?UTF-8?q?be=20paired=20to=20avoid=20rewriting=20leak=20(#2777)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamicAppend/forStrictSandbox.ts | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts index b86abbe8d..781d6c111 100644 --- a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts +++ b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts @@ -59,16 +59,37 @@ function patchDocument(cfg: { sandbox: SandBox; speedy: boolean }) { }; if (speedy) { + const modifications: { + createElement?: typeof document.createElement; + querySelector?: typeof document.querySelector; + } = {}; + const proxyDocument = new Proxy(document, { + /** + * Read and write must be paired, otherwise the write operation will leak to the global + */ set: (target, p, value) => { - (target)[p] = value; + switch (p) { + case 'createElement': { + modifications.createElement = value; + break; + } + case 'querySelector': { + modifications.querySelector = value; + break; + } + default: + (target)[p] = value; + break; + } + return true; }, get: (target, p, receiver) => { switch (p) { case 'createElement': { // Must store the original createElement function to avoid error in nested sandbox - const targetCreateElement = target.createElement; + const targetCreateElement = modifications.createElement || target.createElement; return function createElement(...args: Parameters) { if (!nativeGlobal.__currentLockingSandbox__) { nativeGlobal.__currentLockingSandbox__ = sandbox.name; @@ -87,7 +108,7 @@ function patchDocument(cfg: { sandbox: SandBox; speedy: boolean }) { } case 'querySelector': { - const targetQuerySelector = target.querySelector; + const targetQuerySelector = modifications.querySelector || target.querySelector; return function querySelector(...args: Parameters) { const selector = args[0]; switch (selector) {