Skip to content

Commit a46d5c8

Browse files
committed
Fix possible injection of scriptlets requiring trust from non-trusted sources
Exception filters must never cause actual filters to be created. Reported via email by "syvb": > If you use both ~ and #@# in a filter rule, they cancel each other > out and the filter still runs. But the check for trusted filter rules > ignores all rules with #@#, even if they also use ~. So if you use > both ~ and #@# in the same filter rule it will still run and can use > trusted scriptlets, even when not in a trusted filter list. > > E.g. this filter runs JS on every page, even when not part of a > trusted filter list: > > ~*#@#+js(trusted-create-html, body, <img src=x onerror="alert(document.domain)">) > > idk how big of a problem this is. but having ~ and #@# cancel each other out > doesn't seem like intended behavior anyways? > > thanks > [syvb]
1 parent fe277a4 commit a46d5c8

3 files changed

Lines changed: 10 additions & 6 deletions

File tree

src/js/cosmetic-filtering.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,15 @@ CosmeticFilteringEngine.prototype.compile = function(parser, writer) {
312312
// https://github.com/chrisaljoudi/uBlock/issues/151
313313
// Negated hostname means the filter applies to all non-negated hostnames
314314
// of same filter OR globally if there is no non-negated hostnames.
315+
const isException = parser.isException();
315316
let applyGlobally = true;
316317
for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
317318
if ( bad ) { continue; }
318319
if ( not === false ) {
319320
applyGlobally = false;
320321
}
321-
this.compileSpecificSelector(parser, hn, not, writer);
322+
if ( isException && not ) { continue; }
323+
this.compileSpecificSelector(parser, hn, isException || not, writer);
322324
}
323325
if ( applyGlobally ) {
324326
this.compileGenericSelector(parser, writer);
@@ -427,10 +429,10 @@ CosmeticFilteringEngine.prototype.compileGenericUnhideSelector = function(
427429
CosmeticFilteringEngine.prototype.compileSpecificSelector = function(
428430
parser,
429431
hostname,
430-
not,
432+
isException,
431433
writer
432434
) {
433-
const { raw, compiled, exception } = parser.result;
435+
const { raw, compiled } = parser.result;
434436
if ( compiled === undefined ) {
435437
const who = writer.properties.get('name') || '?';
436438
logger.writeOne({
@@ -442,7 +444,7 @@ CosmeticFilteringEngine.prototype.compileSpecificSelector = function(
442444
}
443445

444446
writer.select('COSMETIC_FILTERS:SPECIFIC');
445-
const prefix = ((exception ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+';
447+
const prefix = isException ? '-' : '+';
446448
writer.push([ 8, hostname, `${prefix}${compiled}` ]);
447449
};
448450

src/js/html-filtering.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,11 @@ htmlFilteringEngine.compile = function(parser, writer) {
352352
let hasOnlyNegated = true;
353353
for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
354354
if ( bad ) { continue; }
355-
const prefix = ((isException ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+';
356355
if ( not === false ) {
357356
hasOnlyNegated = false;
358357
}
358+
if ( isException && not ) { continue; }
359+
const prefix = isException || not ? '-' : '+';
359360
compiledFilters.push([ 64, hn, `${prefix}${compiled}` ]);
360361
}
361362

src/js/scriptlet-filtering-core.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ export class ScriptletFilteringEngine {
160160

161161
for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
162162
if ( bad ) { continue; }
163-
const prefix = ((isException ? 1 : 0) ^ (not ? 1 : 0)) ? '-' : '+';
163+
if ( isException && not ) { continue; }
164+
const prefix = isException || not ? '-' : '+';
164165
writer.push([ 32, hn, `${prefix}${normalized}` ]);
165166
}
166167
}

0 commit comments

Comments
 (0)