AdguardTeam / AdguardTeam/AdguardBrowserExtension

[MV3] $removeparam misses the first query parameter before request; replaceState hides the leak

Aperta
#3,615 1 commento 0 reazioni 1 assegnatario Assegnata a @maximtop Vedi su GitHub
Priority: P4 Version: AdGuard v5.6
Lingua principale
TypeScript
Stelle
4.4k
Fork
449
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

### Please answer the following questions for yourself before submitting an issue

- [x] Filters were updated before reproducing an issue
- [x] I checked the [knowledge base](https://adguard.com/kb/) and found no answer
- [x] I checked to make sure that this issue has not already been filed

### AdGuard Extension version

5.5.2.3 MV3 (TSWebExtension 5.0.3, TSUrlFilter 6.0.3, `@adguard/dnr-converter` 1.1.2)

### Browser version

Google Chrome 151.0.7922.174

### OS version

macOS 26.5.2 (Build 25F84), arm64

### Ad Blocking

No built-in ad-blocking filter is required for the minimal reproduction. Use only the single user rule below.

### Privacy

No built-in privacy filter is required for the minimal reproduction.

### What Tracking protection options do you have enabled?

None are required to reproduce the issue.

### Issue Details

This is an MV3 converter/runtime bug, not a filter-list false positive. A valid named `$removeparam` rule fails before the request when the target is the first query item. The same parameter is removed before the request when placed after another query item. The failed first-position removal is then hidden by a later `history.replaceState` cleanup.

Steps to reproduce:

1. Update the extension and filters.
2. Disable custom subscriptions and duplicate `$removeparam` rules.
3. Add exactly one user rule:

```adblock
||bing.com/search^$removeparam=cvid
```

4. Open the first-position URL:

```text
https://www.bing.com/search?cvid=F1E8F1E8F1E8F1E8F1E8F1E8F1E8F1E8&q=bing-v5523-cvid-first-c5d1&agcontrol=CTRL_V5523_C5D1
```

5. Open the position-swapped URL:

```text
https://www.bing.com/search?q=bing-v5523-cvid-second-c6e2&cvid=A2F9A2F9A2F9A2F9A2F9A2F9A2F9A2F9&agcontrol=CTRL_V5523_C6E2
```

Observed on AdGuard 5.5.2.3:

First-position history:

```text
06:22:32.643Z /search?cvid=F1E8F1E8F1E8F1E8F1E8F1E8F1E8F1E8&q=bing-v5523-cvid-first-c5d1&agcontrol=CTRL_V5523_C5D1
06:22:32.715Z /search?q=bing-v5523-cvid-first-c5d1&agcontrol=CTRL_V5523_C5D1
```

The full first URL was a Bing result-page entry, not merely an uncommitted navigation record. After the address bar was cleaned, the returned Bing HTML still contained the unique `cvid` marker 11 times, including in server-generated `og:url` and RSS links:

```html

```

This directly proves that Bing received the first-position value.

Second-position history:

```text
06:22:32.805Z /search?q=bing-v5523-cvid-second-c6e2&agcontrol=CTRL_V5523_C6E2
```

The second-position marker occurred zero times in the returned HTML. The only result-page URL already lacked it, which is consistent with pre-request DNR removal.

Cross-engine control:

The same position split was reproduced with Google `source`, starting at the bare `google.com` domain:

```text
# source first
06:17:57.913Z https://www.google.com/search?source=AGSRC_V5523_G3A7&q=google-v5523-source-first-g3a7&agcontrol=CTRL_V5523_G3A7
06:17:58.110Z https://www.google.com/search?q=google-v5523-source-first-g3a7&agcontrol=CTRL_V5523_G3A7

# source second
06:17:57.967Z https://www.google.com/search?q=google-v5523-source-second-g4b8&agcontrol=CTRL_V5523_G4B8
```

The first-position marker survived the bare-domain redirect into the `www.google.com` URL and was hidden 197 ms later. With `source` second, the only result URL already lacked it.

An enabled/disabled A/B control confirmed that Bing and Google preserve these unique markers when the relevant AdGuard rules are disabled. Unique search terms and `agcontrol` values were used to avoid cache ambiguity and provide a positive control.

### Expected Behavior

`$removeparam=cvid` should remove `cvid` before the request regardless of whether it is the first, middle, or last query parameter. The remote server must not receive the removed value.

### Actual Behavior

When `cvid` is first, the pre-request DNR condition does not match. Bing receives and echoes the value, and AdGuard removes it from the address bar 72 ms later through the History API cleanup path. When the same parameter is second, pre-request removal works.

This is privacy-significant: the final address bar looks sanitized in both cases even though the first-position value has already left the browser.

### Screenshots

Not applicable. The reproducible navigation timeline and server-echo evidence are included above.

### Additional Information

Environment details:

```text
Device: MacBook Pro (MacBookPro18,1)
Chip: Apple M1 Pro
Memory: 32 GiB
Architecture: arm64
OS: macOS 26.5.2 (Build 25F84)
Browser: Google Chrome 151.0.7922.174
Chrome application binary: Universal (arm64, x86_64)
Extension: AdGuard Browser Extension 5.5.2.3 MV3
```

The current published converter turns the minimal rule into this condition and redirect action:

```json
{
"action": {
"type": "redirect",
"redirect": {
"transform": {
"queryTransform": {
"removeParams": ["cvid"]
}
}
}
},
"condition": {
"urlFilter": "||bing.com/search^*^cvid=",
"resourceTypes": ["main_frame", "sub_frame"]
}
}
```

Likely root cause:

The source rule already ends in `search^`, and the MV3 converter appends `*^cvid=`. Chrome defines `^` as matching one separator character or the end of the URL.

For the first-position URL:

```text
/search?cvid=...
^
```

The source rule's trailing `^` consumes `?`; there is no second separator for the appended `^cvid=` token, so the DNR condition does not match.

For the later-position URL:

```text
/search?q=...&cvid=...
^ ^
```

`?` satisfies the source rule and `&` satisfies the appended parameter token, so the condition matches.

Relevant sources:

- Converter code: https://github.com/AdguardTeam/tsurlfilter/blob/9e655fb0f92a85e5be60bf643125cacd859b633c/packages/dnr-converter/src/rule-converters/regular-rule-converter.ts#L640-L653
- Chrome URL-filter syntax: https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest#url_filter_syntax
- History cleanup implementation: https://github.com/AdguardTeam/tsurlfilter/blob/9e655fb0f92a85e5be60bf643125cacd859b633c/packages/tswebextension/src/lib/common/content-script/remove-param-main-world.ts#L280-L349
- Browser Extension 5.5.2.3 dependency versions: https://github.com/AdguardTeam/AdguardBrowserExtension/blob/v5.5.2.3/package.json#L145-L153

Running the published converter 1.1.2 directly produced the same `...search^*^param=` condition without conversion errors. The current valued-`$removeparam` test checks `redirect.removeParams`, but does not assert the generated `condition.urlFilter` or test first-position versus later-position URL matching:

https://github.com/AdguardTeam/tsurlfilter/blob/9e655fb0f92a85e5be60bf643125cacd859b633c/packages/dnr-converter/test/src/filter-converter/filter-converter.test.ts#L92-L109

Related issues checked:

- #3444 / AG-50852 introduced the current parameter-aware URL-filter construction. This appears to be an uncovered edge case of that fix, not a duplicate: https://github.com/AdguardTeam/AdguardBrowserExtension/issues/3444
- #188 added History API processing for SPA navigation. It explains why the address bar later looks clean, but does not prevent the original network request: https://github.com/AdguardTeam/tsurlfilter/issues/188
- This is not the one-redirect/multiple-rule limitation in #3034. The minimal reproduction has exactly one matching `$removeparam` rule, and changing only the parameter position changes the result: https://github.com/AdguardTeam/AdguardBrowserExtension/issues/3034

No exact duplicate or open fixing PR was found as of 2026-08-27.

Suggested regression test:

```adblock
||example.com/path^$removeparam=foo
```

Verify both requests:

```text
https://example.com/path?foo=DROP&control=KEEP
https://example.com/path?control=KEEP&foo=DROP
```

In both cases, `foo` must be removed before any network request.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.