How uBlock Origin Dynamic Filtering Overrides Static Filter Lists

uBlock Origin's dynamic filtering engine evaluates rules after static filter lists and can override any static block with a user-defined allow rule, giving users granular, session-specific control over network requests.

The gorhill/uBlock repository implements a two-layer filtering architecture where static filter lists are applied first, followed by dynamic filtering rules. Understanding how uBlock Origin dynamic filtering overrides static filter lists is essential for advanced users who need to create exceptions to built-in blocklists without modifying the underlying filter files.

How Static and Dynamic Filtering Work Together in uBlock Origin

uBlock Origin processes network requests through two distinct engines that operate sequentially. The static engine runs first, followed by the dynamic engine, which has the final authority to override blocking decisions.

The Static Filtering Engine (staticNetFilteringEngine)

The static filtering engine loads pre-compiled filter lists such as EasyList and uBlock Origin's own lists. These immutable rules are processed first for every network request. The engine is implemented in src/js/static-net-filtering.js and provides the matchRequest() method to check URLs against compiled filters.

The Dynamic Filtering Engines (sessionURLFiltering and sessionFirewall)

After static evaluation, uBlock Origin consults two dynamic filtering engines instantiated in src/js/filtering-engines.js:

  • sessionURLFiltering: Handles per-session URL-specific rules (e.g., example.com * allow) set via the Dynamic Filtering pane.
  • sessionFirewall: Manages host-based dynamic rules that apply to specific domains or globally.

These engines are mutable for the duration of the browser session and are evaluated after every static match.

Where Dynamic Filtering Overrides Static Blocks in the Source Code

The override logic is implemented at specific interception points in the codebase where the code explicitly checks dynamic rules after static filtering has occurred.

CSP Injection Override in traffic.js

In src/js/traffic.js (lines 1090–1106), uBlock Origin checks dynamic allow rules before injecting Content Security Policy headers. If a dynamic allow rule exists, the CSP injection is skipped, effectively overriding the static filter that triggered it:

// URL filtering `allow` rules override static filtering.
if ( cspSubsets.length !== 0 &&
     sessionURLFiltering.evaluateZ(fctxt.getTabHostname(),
                                   fctxt.url, 'csp') === 2 ) { … }

// Dynamic filtering `allow` rules override static filtering.
if ( cspSubsets.length !== 0 &&
     µb.userSettings.advancedUserEnabled &&
     sessionFirewall.evaluateCellZY(fctxt.getTabHostname(),
                                   fctxt.getTabHostname(),
                                   '*') === 2 ) { … }

The evaluateZ() and evaluateCellZY() methods return 2 when an allow rule matches, signaling the override.

In src/js/tab.js (lines 200–215), popup blocking follows the same pattern. After the static engine determines a popup should be blocked, the code checks sessionFirewall for an allow rule:

result = sessionFirewall.evaluateCellZY(
    fctxt.getTabHostname(),
    fctxt.getHostname(),
    popupType);
if ( result === 2 ) {
    fctxt.filter = sessionFirewall.toLogData();
    return 2;                // dynamic allow wins
}

If result === 2, the popup is permitted despite any static filter match.

Practical Examples of Dynamic Override

Creating an Allow Rule in the UI

To override a static block using uBlock Origin's dynamic filtering:

  1. Open the uBlock Origin dashboard (Ctrl+Shift+U).
  2. Switch to "Dynamic Filtering".
  3. In the "Allow" column, type a hostname (e.g., example.com) and press Enter.

This creates the rule:

example.com * allow

The rule is stored in sessionFirewall and will override any static block for example.com and its subdomains for the current browser session.

Programmatically Checking the Override Logic

You can observe the override mechanism programmatically using the extension's internal APIs:

// Assume we are on a page that requests a blocked resource.
let ctx = µb.filteringContext.fromWebrequestDetails({
    url: "https://ads.example.com/banner.js",
    tabId: browser.tabs.getCurrent().id,
    type: "script"
});

// Static engine result (normally 1 = block)
let staticResult = staticNetFilteringEngine.matchRequest(ctx, 0b0001);

// Dynamic URL allow (session rule added from UI)
let dynamicResult = sessionURLFiltering.evaluateZ(
    ctx.getTabHostname(),
    ctx.url,
    'script');   // returns 2 if an allow rule matches

console.log({ staticResult, dynamicResult });
// If dynamicResult === 2, the request will be allowed despite staticResult === 1.

When dynamicResult === 2, the dynamic allow rule takes precedence over the static block (staticResult === 1).

Summary

  • Static filtering runs first: The staticNetFilteringEngine in src/js/static-net-filtering.js processes compiled filter lists like EasyList before any dynamic rules are considered.
  • Dynamic filtering overrides blocks: The sessionURLFiltering and sessionFirewall engines in src/js/filtering-engines.js are consulted after static matching. When evaluateZ() or evaluateCellZY() returns 2 (allow), the static block is overridden.
  • Implementation locations: Override logic is explicitly implemented in src/js/traffic.js for CSP injection and src/js/tab.js for popup handling.
  • One-way override: Only dynamic allow rules override static block rules. Dynamic block rules do not override static allow rules (exception filters).

Frequently Asked Questions

Can dynamic blocking rules override static allow rules?

No, dynamic blocking rules cannot override static allow rules. The override mechanism in uBlock Origin is unidirectional: dynamic allow rules (return value 2 from evaluateZ() or evaluateCellZY()) can supersede static blocks, but static allow rules (exception filters like @@) already permit requests and cannot be blocked by dynamic rules.

Where are dynamic filtering rules stored?

Dynamic filtering rules are stored in memory for the duration of the browser session via two engine instances defined in src/js/filtering-engines.js: sessionURLFiltering for URL-specific rules and sessionFirewall for host-based rules. These correspond to the rules you create in the Dynamic Filtering pane of the uBlock Origin dashboard.

Does dynamic filtering affect cosmetic filters?

No, dynamic filtering only affects network requests (blocking or allowing URLs and hostnames). Cosmetic filters (element hiding rules) are handled by a separate cosmetic filtering engine and are not influenced by dynamic network filtering rules. Dynamic filtering operates on the network layer in traffic.js and tab.js, while cosmetic filtering operates on the DOM.

How does uBlock Origin prioritize multiple dynamic rules?

uBlock Origin evaluates dynamic rules in a specific hierarchy. URL-specific rules in sessionURLFiltering are checked first using evaluateZ(). If no match is found, host-based rules in sessionFirewall are evaluated using evaluateCellZY(). The first matching rule determines the action, with allow rules (return value 2) taking precedence over block rules when overriding static filters.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →