The quoted email below was sent to ubo-security at raymondhill dot net:
=====
Dear Raymond,
I am writing to report a potential Regular Expression Denial of Service (ReDoS)
vulnerability in the 1p-filters.js script of uBlock Origin. The vulnerability
occurs due to the use of the regular expression /\s+$/, which is used to remove
trailing whitespace. This issue can lead to a denial of service when processing
strings with a large number of trailing spaces, potentially causing a browser to
freeze.
Affected file(s)
js/1p-filters.js
Vulnerable pattern(s)
Lines 131 and 167: /\s+$/
Description of the issue
The regular expression /\s+$/ is applied to remove trailing whitespace in user‑
provided content. However, when the content has a large number of spaces
(e.g., ~100,000), this pattern causes excessive backtracking in the regular
expression engine, resulting in performance degradation and UI freezing. This is
a classic ReDoS attack vector.
Steps to reproduce
1. Open the uBlock Origin dashboard and navigate to the My filters tab.
2. Run the following code in the browser's DevTools Console or as a bookmarklet.
3. Observe the UI freezing for several seconds or even longer, depending on the
number of spaces used.
PoC (Proof of Concept)
/**
* poc.js — triggers ReDoS in 1p-filters.js
* Expected: <1 ms; Actual: several seconds – UI freeze
*/
(() => {
const payload = " ".repeat(100000) + "!"; // 100,000 spaces + sentinel
const run = () => {
if (!window.cmEditor) {
console.error("cmEditor not ready");
return;
}
// Inject payload into the editor
cmEditor.setValue(payload);
console.time("ReDoS");
// Call the vulnerable function (mirroring getEditorText)
cmEditor.getValue().replace(/\s+$/, '');
// Alternatively, simulate a realistic user flow:
// document.querySelector('#userFiltersApply').click();
console.timeEnd("ReDoS");
};
if (document.readyState === "complete") {
run();
} else {
window.addEventListener("load", run, { once: true });
}
})();
Impact
This issue can significantly degrade the user experience, causing the page to
become unresponsive. If an attacker can inject this malicious string into the
page (for example, through XSS or other attacks), it could lead to a denial of
service (DoS). This vulnerability can be triggered repeatedly, causing the
browser to hang indefinitely.
Suggested fix
The issue can be mitigated by replacing /\s+$/ with a more efficient solution,
such as a look‑behind assertion /(?<=\S)\s+$/ (available in modern browsers)
which ensures no backtracking occurs, or using trimEnd() for legacy support:
// Example of using look-behind:
cmEditor.setValue(text.replace(/(?<=\S)\s+$/, '') + '\n\n');
// Alternatively, using trimEnd():
cmEditor.setValue(text.trimEnd() + '\n\n');
Additional information
If required, I am happy to assist in testing or provide more information.
Please feel free to contact me for further clarification.
Best regards,
[redacted]
=====
Related issues:
- https://github.com/uBlockOrigin/uBlock-issues/issues/3161
- https://github.com/uBlockOrigin/uBlock-issues/discussions/2895#discussioncomment-8504374
Two checkboxes have been added to the "My filters "pane:
1. A checkbox to wholly disable/enable "My filters". This is equivalent
to the checkbox for "My filters" in "Filter lists" pane.
2. A checkbox to enable/disable the trustworthiness of the content
of "My filters". Default to untrusted.
Since toggling these checkboxes requires reloading all filter lists,
their new state must be committed through the "Apply changes" button.
Additionally: a "book" icon has been added to the top-right of the
dashboard, which is a link to the wiki according to whichever pane is
currently active.
`uDom` is old and crusty and `dom` is meant as replacement. The
goal of `dom` is to be simpler and mainly just convenience
methods for handling the DOM with vanilla JS -- this is not a
framework.
Additionally, removed keyboard shortcuts pane which was useful
only on very old versions of Firefox.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/1433
The new "extraTrustedSiteDirectives" policy is an array
of strings, each of which is parsed as a trusted-site
directive to append to a user's own set of trusted-site
directives at launch time.
The added trusted-site directives will be considered as
part of the default set of directives by uBO.
Related commit:
- 453f5450b6
The changes in this commit are mostly related
to the "Filter lists" pane.
An eye icon has been added, which purpose is
to view the content of a list. Clicking on the
name of the list will toggle the list's
checkbox.
Related issue:
- https://github.com/gorhill/uBlock/issues/3271
When navigating away by clicking another pane tab button,
there will be an embedded warning, which can be ignore
in order to proceed to the new pane, or dismissed by
either clicking on the "Stay" button or anywhere else
in the dashboard.
When navigating away by trying to close the tab, there will
be a built-in browser warning asking for confirmation.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/214
Built-in whitelist directives are now rendered differently
than user-defined whitelist directives. Also, removing a
built-in whitelist directive will only cause that directive
to be commented out, so that users do not have to remember
built-in directives should they want to bring them back.
Related issue:
https://github.com/uBlockOrigin/uBlock-issues/issues/494
The built-in per-site switch rule
`no-scripting: behind-the-scene false` has been removed,
it should not ever be needed since there will always be a
valid root context for main- and sub-frames.
Benefits:
- Cross browser solution (however only for relatively new browsers)
- Doesn't need extra permission in Chrome
If the browser doesn't suppor the download attribute, then a new tab will
be opened with the exported data.
Other changes:
- Start the download only if the data is not empty (previously the
download started anyway)
- Reorder code in vapi-client.js for Safari, so unnecessary code doesn't
run on extension pages
.jshintrc's otion-set is a personal choice, merely a suggestion.
Beside that, it includes some common globals for specific browsers, so
there's no need to set the globals in every .js file.
In order to force strict coding, "use strict" directive was added into
every .js file.