Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,56 @@

Releases of this community fork. The upstream uBlock Origin changelog follows further below.

## Unreleased

### Honest filter compilation

Stock lists (build time):
- Filters that cannot become DNR rules are now counted and reported instead of being dropped silently, with the exceptions listed under *Not yet done* below. Before, the build log said `Unsupported: 0` for every list.
- The build log shows `Unsupported: N` for each list with a count per reason code, and a total per reason for all rulesets at the end.
- `ruleset-details.json` adds `rules.rejectedReasons` and `filters.converted`.
- Source filters are counted, not the rule entries they compile into.
- With the list snapshot of 23 September 2026 (built on 24 September), 1,213 filters in 32 of the 55 lists are reported. Most are `$redirect-rule` (530) and entity or regex hostnames in `domain=`, `to=` or `denyallow=` (337).
- About 1,155 of them are valid filters that DNR cannot express. The other 58 are invalid filters that uBlock Origin rejects too; 51 of those are cosmetic or scriptlet filters with syntax errors.
- `tools/validate-mv3.mjs` rejects a package when the reported counts do not match it: rule counts against the packaged rulesets, per-reason counts against the total, and the `Unsupported` lines of `log.txt`. In development builds it also compares them with the compiler output.
- The dashboard tooltip of each stock list counts the filters actually converted. For uBlock filters it drops from 10,498 to 7,847: the old number counted a filter once per resource type and included filters that never become DNR rules. A second line gives the number of rejected filters, translated into the ten maintained languages.
- `##^responseheader()` filters remove the header from responses of the hostnames they name. They used to act on navigations started from those sites instead.
- They apply to all resource types, as in uBlock Origin, and honour exceptions within the same list.
- A filter whose only hostnames are entities (`example.*`) or regexes is reported instead of becoming a rule for every site.
- `removeparam=~name` is reported as unsupported instead of becoming a rule that never matches. Regex values written as `/re/i` or with the legacy `|` prefix are reported as regex.
- Every built-in redirect resource is packaged and web-accessible, so `redirect=` filters in imported lists and personal filters can use all of them.
- `click2load.html` cannot work through DNR. Both compilers reject it, and `rulesets/redirect-resources.json` lists it as unavailable.
- The build fails when a resource file is missing.

Imported lists and personal filters (runtime compiler):
- `$requestheader` is rejected. It used to compile into an unconditional block, or an unconditional allow for `@@` filters.
- `$empty` and `$mp4` redirect to the `empty` and `noop-1s.mp4` resources, as in stock lists, instead of blocking every request type. Redirect exceptions (`@@…$redirect`, `@@…$empty`, `@@…$mp4`) are rejected.
- A bare `$removeparam` (or `$removeparam=|`) removes the whole query. It used to remove nothing.
- `@@…$uritransform=…` is rejected. It used to compile into a real redirect, and exceptions skip the trusted-source check.
- `$permissions` with several policies separated by `|` joins them with `, `. The `|` used to stay in the header value, which made the header invalid.
- `important` is no longer dropped. On `removeparam` and `uritransform` it gives priority 2, which stays below every block; on `csp` and `permissions` it gives priority 31, as in stock lists.
- `||host^$to=x` requires both the hostname pattern and `to=`. It used to block every request to `x`.
- `redirect=click2load.html` is rejected, as in stock lists.
- Imported lists compiled by an earlier version are recompiled with these rules (compiled-cache revision 4) instead of keeping their old output.

Both compilers:
- A `$removeparam` filter with `domain=` plus a hostname pattern or `to=` no longer strips parameters on every page load of the `domain=` sites. Its page-load rule keeps only the hostnames in both lists, and is dropped when none remain. Two over-broad rules in uBlock filters are gone.

Not yet done:
- Negated entity or regex hostnames in stock filters (`domain=~example.*`, and likewise in `to=` and `denyallow=`) are still dropped silently, with no warning and no count. The rule then also applies to the sites it should exclude. 187 filters in the list snapshot are affected.
- Entity hostnames removed from partly converted stock filters are only logged as warnings, and only for non-regex static rules.
- There is no per-reason view of rejected filters in the dashboard.

### Documentation and tests

- New [research into lifting MV3 limits](docs/MV3-LIMITS-RESEARCH-2026-09-24.md) (Vietnamese). It covers what cannot be done in Chrome, the Standard / Experimental / Firefox tiers, measurements on Chrome 153 and an 11-step roadmap.
- Corrected documentation:
- `chrome.dns` is granted on Chrome Stable 153 with `--allowlisted-extension-id` to an extension whose manifest declares `dns`, but returns one IP address and never a CNAME chain. The Experimental package does not declare `dns`.
- Large-media blocking can be expressed with two DNR `Content-Length` rules, at an approximate threshold. The probe blocked from 50,000 bytes; uBlock Origin's default is 51,200 bytes and can be changed, and an exact threshold needs more patterns (not tried). Only responses that carry the header are covered, and the size is the compressed size.
- Remote fonts and `report-uri` CSP reports can be blocked by DNR; they are missing features, not browser limits.
- The `chrome.debugger` route misses responses built by a page's service worker and the first document of a new tab, prompts for Local Network Access on local iframes, and needs auto-attach for subresources of cross-site iframes.
- New tests: `tools/test-stock-compiler-honesty.mjs` and `tools/test-runtime-filter-options.mjs`.

## 1.2.0

### Automatic updates
Expand Down
13 changes: 12 additions & 1 deletion docs/EXPERIMENTAL-WEBREQUEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This optional Windows/Chromium package adds **synchronous network blocking for saved dynamic-firewall rules**. It uses the same firewall editor, hostname precedence, block/allow/noop rules and local Public Suffix List as the standard package. DNR remains active. The additional listener can evaluate a newly visited domain without waiting for DNR's learned-domain update.

This is an implemented firewall supplement, **not a port of the complete uBlock Origin network engine or an unlimited MV3 mode**. Imported, personal and packaged static network filters still use the existing DNR compiler. DNR rule and regex limits, the firewall editor's limits, response-body restrictions and unsupported inline-script filtering still apply. Compare against [the full uBO compatibility matrix](FEATURE-MATRIX.md).
This is an implemented firewall supplement, **not a port of the complete uBlock Origin network engine or an unlimited MV3 mode**. Imported, personal and packaged static network filters still use the existing DNR compilers, which report most of the filters they cannot convert with a reason code. DNR rule and regex limits, the firewall editor's limits, response-body restrictions and unsupported inline-script filtering still apply. Compare against [the full uBO compatibility matrix](FEATURE-MATRIX.md). Which of these limits this package could lift, and at what cost, is analysed in the [MV3 limits research of 24 September 2026](MV3-LIMITS-RESEARCH-2026-09-24.md) (Vietnamese).

<details>
<summary>Actual Chrome diagnostics and native blocking evidence</summary>
Expand Down Expand Up @@ -86,8 +86,19 @@ The capability probe on **Google Chrome 152.0.7977.76** compared the same tiny t

Chrome's supported MV3 `webRequestBlocking` route remains policy-installed extensions. The allowlist route is an experimental startup switch; it does not turn the extension into a policy installation. In particular, Chromium checks policy location separately for Promise-based blocking responses. [Chrome webRequest](https://developer.chrome.com/docs/extensions/reference/api/webRequest#permissions), [Chromium 152 implementation](https://github.com/chromium/chromium/blob/152.0.7977.76/extensions/renderer/api/web_request_natives.cc#L83).

**Re-check on Google Chrome 153.0.8010.53, 24 September 2026.** Small test extensions were run in fresh temporary profiles, which were deleted afterwards:

- The switch still grants `webRequestBlocking` to an unpacked MV3 extension. It also granted `dns` to a test extension whose manifest declares it; this package does not declare `dns`. Without the switch, neither is granted. Cancel, redirects (including `main_frame`), and adding or removing response headers took effect.
- Chromium implements the switch as a test hook, [`IsAllowlistedForTest`](https://github.com/chromium/chromium/blob/153.0.8010.53/extensions/common/features/simple_feature.cc#L735-L743). It skips every allowlist and install-location check for that ID, not only the one for `webRequestBlocking`. The switch is on the [list of flags](https://github.com/chromium/chromium/blob/153.0.8010.53/chrome/browser/ui/startup/bad_flags_prompt.cc#L119-L121) that show the unsupported-flag warning bar, and Chrome can remove it in any release.
- The extension is still not policy-installed. [Promise responses are ignored](https://github.com/chromium/chromium/blob/153.0.8010.53/extensions/renderer/api/web_request_natives.cc#L92-L102): requests whose listener returned a Promise (immediate or delayed cancel, `async` function, redirect) all reached the server, while the same decisions returned synchronously took effect.
- `chrome.dns.resolve()` returns one IP address and never a CNAME chain, so the grant does not enable CNAME uncloaking.
- DNR block and redirect decisions still win over the listener. DNR rules conditioned on response headers act at `onHeadersReceived`, after the request was sent.
- Relaunching the same dedicated profile with the switch across browser restarts, and a cold browser start, were not re-tested.

A full native uBO engine would additionally need one coherent compiled corpus for every enabled stock/imported/personal source, cross-source exceptions and `$badfilter`, request modifiers, startup recovery and engine-switch rollback. The [r58Playz/uBlock-mv3 project](https://github.com/r58Playz/uBlock-mv3#how-it-works) demonstrates that broader architecture; this package does not silently adopt its startup cancellation/reload behavior.

The research measured what such an engine would cost here, on one machine (AMD Ryzen 5 5600H, 8 GB RAM) and one Chrome build. Restoring uBO's `static-net-filtering.js` from an IndexedDB snapshot took 60–75 ms per real worker start with the default lists (138,922 filters) and 75–95 ms with 23 lists (203,598 filters). With realistic pauses between page loads (5 or 35 seconds), up to 44 of a test page's roughly 150 requests, always including its `main_frame` request, passed the listener before the engine was ready; only DNR filtered them. Building the engine synchronously at the worker's top level made Chrome hold the requests instead (0 of 32 passed) at a delay of 100–115 ms, measured with the default lists only. Matching took 30–150 µs per request over the first few hundred requests after a start and 6–8 µs once warm; worker memory grew by 9–16 MiB. DNR stays the always-on baseline even so: Chrome can be started without the switch, user state such as filtering modes and enabled lists is still read asynchronously, and a cold browser start was not measured.

## Validation of the integrated package — 6 September 2026

The release pipeline passed with **Node 22.22.0 / npm 11.19.1**: `npm ci`, **43 test programs**, lint, standard and experimental Chromium builds, both release validators and verification of every ZIP entry. The Windows PowerShell 5.1 launcher dry-run also passed. An existing development dependency advisory was resolved by updating `@humanfs/node` to 0.16.8 and its required dependencies; `npm audit` reports zero known vulnerabilities. [Upstream advisory](https://github.com/advisories/GHSA-p498-v437-472g).
Expand Down
Loading