-
Notifications
You must be signed in to change notification settings - Fork 79
Description
Problem
When a Declarative Net Request (DNR) rule redirects a subresource (e.g., /ad.js), pages can detect the redirect by calling fetch(url, { redirect: "error" }). Because the browser exposes the DNR action as a network redirect, the promise rejects—revealing that a blocker intervened.
Impact
Sites can trivially fingerprint users running blockers. This defeats the goal of using redirects to keep pages functional without leaking blocker presence.
Repro (minimal)
- DNR rule (MV3):
- In the page console:
fetch("/ad.js", { redirect: "error" })
.then(r => console.log("resolved", r.status, r.redirected))
.catch(e => console.log("rejected", String(e)));Actual: Promise rejects because a redirect occurred and redirect: "error" forbids it.
Expected: Promise resolves (e.g., 200 OK) with no observable redirect, so the redirect cannot be used to detect blocking.
Proposed fix
For subresource requests affected by DNR redirect, return a synthetic 200 response (body = redirect target) without exposing a network redirect to page scripts:
fetch(..., { redirect: "error" })does not rejectResponse.redirected === false- No redirect hop visible to page JS
This could be the default for DNR redirects or an opt-in flag (e.g., "syntheticResponse": true).
References
[ { "id": 1, "priority": 1, "action": { "type": "redirect", "redirect": { "extensionPath": "/empty.js" } // or data URL }, "condition": { "urlFilter": "/ad.js", "resourceTypes": ["script"] } } ]