Skip to content

Commit fe74481

Browse files
committed
Add prevent-innerHTML scriptlet
@description Conditionally prevent assignment to `innerHTML` property. @param [selector] Optional. The element must matches `selector` for the prevention to take place. @param [pattern] Optional. A pattern to match against the assigned value. The pattern can be a plain string, or a regex. Prepend with `!` to reverse the match condition. As discussed with filter list volunteers.
1 parent 98b011f commit fe74481

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

src/js/resources/prevent-innerHTML.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*******************************************************************************
2+
3+
uBlock Origin - a comprehensive, efficient content blocker
4+
Copyright (C) 2025-present Raymond Hill
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see {http://www.gnu.org/licenses/}.
18+
19+
Home: https://github.com/gorhill/uBlock
20+
21+
*/
22+
23+
import { registerScriptlet } from './base.js';
24+
import { safeSelf } from './safe-self.js';
25+
26+
/**
27+
* @scriptlet prevent-innerHTML
28+
*
29+
* @description
30+
* Conditionally prevent assignment to `innerHTML` property.
31+
*
32+
* @param [selector]
33+
* Optional. The element must matches `selector` for the prevention to take
34+
* place.
35+
*
36+
* @param [pattern]
37+
* Optional. A pattern to match against the assigned value. The pattern can be
38+
* a plain string, or a regex. Prepend with `!` to reverse the match condition.
39+
*
40+
* */
41+
42+
export function preventInnerHTML(
43+
selector = '',
44+
pattern = ''
45+
) {
46+
const safe = safeSelf();
47+
const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern);
48+
const matcher = safe.initPattern(pattern, { canNegate: true });
49+
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
50+
if ( current === undefined ) { return; }
51+
const shouldPreventSet = a => {
52+
if ( selector !== '' ) {
53+
if ( typeof this.matches === 'function' === false ) { return false; }
54+
if ( this.matches(selector) === false ) { return false; }
55+
}
56+
return safe.testPattern(matcher, a);
57+
};
58+
Object.defineProperty(Element.prototype, 'innerHTML', {
59+
get: function() {
60+
return current.get
61+
? current.get.call(this)
62+
: current.value;
63+
},
64+
set: function(a) {
65+
if ( shouldPreventSet(a) ) {
66+
safe.uboLog(logPrefix, 'Prevented');
67+
} else if ( current.set ) {
68+
current.set.call(this, a);
69+
}
70+
current.value = a;
71+
},
72+
});
73+
}
74+
registerScriptlet(preventInnerHTML, {
75+
name: 'prevent-innerHTML.js',
76+
dependencies: [
77+
safeSelf,
78+
],
79+
});

src/js/resources/scriptlets.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
import './attribute.js';
2424
import './href-sanitizer.js';
2525
import './noeval.js';
26+
import './prevent-innerHTML.js';
27+
import './prevent-settimeout.js';
2628
import './replace-argument.js';
2729
import './spoof-css.js';
28-
import './prevent-settimeout.js';
2930

3031
import { runAt, runAtHtmlElementFn } from './run-at.js';
3132

0 commit comments

Comments
 (0)