Skip to content

DNR redirects make fetch(..., { redirect: "error" }) reject → easy blocker detection #868

@chrmod

Description

@chrmod

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)

  1. DNR rule (MV3):
[
  {
    "id": 1,
    "priority": 1,
    "action": {
      "type": "redirect",
      "redirect": { "extensionPath": "/empty.js" } // or data URL
    },
    "condition": {
      "urlFilter": "/ad.js",
      "resourceTypes": ["script"]
    }
  }
]
  1. 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 reject
  • Response.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

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triage: chromeChrome needs to assess this issue for the first timeneeds-triage: firefoxFirefox needs to assess this issue for the first timeneeds-triage: safariSafari needs to assess this issue for the first timetopic: dnrRelated to declarativeNetRequest

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions