Skip to content

Build1 publisher3 min readPublished

Firefox and Edge keep using a proxy's old username until its hostname changes

RoamProxy's extension mints a new proxy hostname on every save because Firefox and Edge kept reusing connections authenticated with the old username. Any gateway that routes by username on one host and port hits the same silent failure.

The Engineer · Build desk

Illustration accompanying Firefox and Edge keep using a proxy's old username until its hostname changes

What happened

  • RoamProxy, a pay-as-you-go proxy service, shipped a browser extension for Firefox and Microsoft Edge that sets exit country and IP mode from a popup.
  • Its gateway exposes one host and port and reads targeting from the username, so alice-country-de-session-k3j9 means a sticky German exit.
  • In testing, switching the popup from Japan to the US left an IP checker showing a Japanese exit until the browser was restarted.
  • Firefox's per-request proxy.onRequest API hit the same problem, because the browser kept reusing the tunnel authenticated with the old username.
  • RoamProxy's fix points a wildcard DNS record, *.gw.roamproxy.com, at the same gateway so each settings save can connect through a new subdomain.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint An extension cannot flush Chromium's connection pool or credential cache, so the only lever left is changing the proxy host the browser sees.
  • exposure A user can browse through a Japanese exit while the popup shows the US, and the extension gets no error it could catch.
  • decision Providers that sell country or session targeting through the username on one endpoint now have to serve their gateway under many hostnames, or accept stale exits in browsers.

Chromium holds two pieces of state that a username-routed gateway runs into. RoamProxy's Edge build installs a fixed proxy with chrome.proxy.settings.set and answers the 407 challenge in webRequest.onAuthRequired, which under Manifest V3 needs the webRequestAuthProvider permission [1][3]. After the popup moves from Japan to the US, requests go through this sequence:

1. The browser reuses its pool of open connections to the proxy. A CONNECT tunnel authenticated with the Japan username stays authenticated as Japan for as long as it lives [5]. 2. When Chromium does open a new connection, it looks up the credentials cached for that proxy host and port and replays the Japan pair [6]. 3. The onAuthRequired handler holding the US username is never called [6]. 4. The Japan username is still valid, so the gateway accepts it [8].

The credential cache is keyed on host and port [6]. Changing the username touches neither.

Firefox's proxy.onRequest looked like a way around this. It is called for every request and returns either an http host and port or a direct route, with no global setting [9]. "I wrote the first Firefox build on the assumption that the per-change hostname trick was unnecessary there," the post's author wrote [10]. The first live test showed the same problem [9]. The post does not say whether Firefox also caches credentials per host the way Chromium does [9].

The Chromium fix is one template string in background.js: host = `x${Date.now()}.gw.roamproxy.com`, installed as a fixed_servers rule with scheme http on port 41080 [11]. The comment above it states the intent: "A fresh hostname per change: new connection pool, new auth cache entry." [11] The Firefox build writes the same timestamped value to cfg.proxyHost and returns it from onRequest. The popup code is identical between the two builds, and only the background script differs [13].

It works with each browser's own cache key, and the gateway needed no change because it ignores the hostname a client connected through [12]. Each switch now starts cold. The first request after a change opens a new proxy connection and meets a fresh 407, answered by the handler with the current username [16].

For a provider that owns its DNS, I think one wildcard record is a fair price. The fix transfers only where two things hold. The gateway must accept any hostname, and whoever ships the extension must control a DNS zone that can point a wildcard at it [12]. A third party writing an extension for someone else's single-hostname gateway cannot meet either condition.

The "new IP" button depends on the same username scheme. In fixed-IP mode it generates four candidate session ids, probes each through a small check endpoint in parallel, and keeps the one with the lowest latency [15]. Each candidate is a separate username against the same gateway host and port [2].

"If you are building anything that changes proxy identity without changing proxy host, budget for this," the post's author wrote. "Both browsers will make your first ten minutes of testing look like success." [14]

What to watch

  • An extension API in Chromium or Firefox to drop cached proxy credentials or close pooled tunnels; with one, the per-save hostname would be unnecessary.
  • Whether RoamProxy reports long-session effects of minting a hostname per save, such as how many pools and cache entries build up before a browser restart.
  • Whether other username-routed proxy services ship browser extensions with the same hostname workaround or a different one.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories