From 0971025b21155f07955ed703143c3324c732cf03 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 11 Dec 2022 10:08:10 -0500 Subject: [PATCH] Use Blob URLs to reliably inject scriptlets Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/235 Fixed as suggested by , to safely bypass a page's own CSP. --- src/js/contentscript.js | 11 ++++++++--- src/js/redirect-engine.js | 4 ++-- src/js/scriptlet-filtering.js | 21 ++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/js/contentscript.js b/src/js/contentscript.js index 6576bce53cac0..ee8f7aaee2964 100644 --- a/src/js/contentscript.js +++ b/src/js/contentscript.js @@ -465,16 +465,21 @@ vAPI.SafeAnimationFrame = class { vAPI.injectScriptlet = function(doc, text) { if ( !doc ) { return; } - let script; + let script, url; try { + const blob = new self.Blob([ text ], { type: 'text/javascript' }); + url = self.URL.createObjectURL(blob); script = doc.createElement('script'); - script.appendChild(doc.createTextNode(text)); + script.src = url; (doc.head || doc.documentElement || doc).appendChild(script); } catch (ex) { } if ( script ) { script.remove(); - script.textContent = ''; + script.src = ''; + } + if ( url ) { + self.URL.revokeObjectURL(url); } }; diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js index 455de0d376723..ef3305559db2e 100644 --- a/src/js/redirect-engine.js +++ b/src/js/redirect-engine.js @@ -35,7 +35,7 @@ import { const extToMimeMap = new Map([ [ 'gif', 'image/gif' ], [ 'html', 'text/html' ], - [ 'js', 'application/javascript' ], + [ 'js', 'text/javascript' ], [ 'mp3', 'audio/mp3' ], [ 'mp4', 'video/mp4' ], [ 'png', 'image/png' ], @@ -46,7 +46,7 @@ const extToMimeMap = new Map([ const typeToMimeMap = new Map([ [ 'main_frame', 'text/html' ], [ 'other', 'text/plain' ], - [ 'script', 'application/javascript' ], + [ 'script', 'text/javascript' ], [ 'stylesheet', 'text/css' ], [ 'sub_frame', 'text/html' ], [ 'xmlhttprequest', 'text/plain' ], diff --git a/src/js/scriptlet-filtering.js b/src/js/scriptlet-filtering.js index f7ff31b714e90..0b0c3c4f4d8b9 100644 --- a/src/js/scriptlet-filtering.js +++ b/src/js/scriptlet-filtering.js @@ -97,19 +97,25 @@ const contentscriptCode = (( ) => { ) { return; } - let script; + let script, url; try { - script = doc.createElement('script'); - script.appendChild(doc.createTextNode( - decodeURIComponent(scriptlets)) + const blob = new self.Blob( + [ decodeURIComponent(scriptlets) ], + { type: 'text/javascript' } ); + url = self.URL.createObjectURL(blob); + script = doc.createElement('script'); + script.src = url; (doc.head || doc.documentElement).appendChild(script); self.uBO_scriptletsInjected = true; } catch (ex) { } if ( script ) { script.remove(); - script.textContent = ''; + script.src = ''; + } + if ( url ) { + self.URL.revokeObjectURL(url); } if ( typeof self.uBO_scriptletsInjected === 'boolean' ) { return 0; } }.toString(), @@ -177,10 +183,7 @@ const lookupScriptlet = function(rawToken, reng, toInject) { } else { token = `${token}.js`; } - content = reng.resourceContentFromName( - token, - 'application/javascript' - ); + content = reng.resourceContentFromName(token, 'text/javascript'); if ( !content ) { return; } if ( args ) { content = patchScriptlet(content, args);