Skip to content

feat(browsers): chromium makes no background requests of its own (FD-5113, M8.52) - #596

Merged
earakely-scale merged 6 commits into
mainfrom
edgararakelyan/fd-5113-chromium-background-requests
Nov 10, 2026
Merged

earakely-scale merged 6 commits into
mainfrom
edgararakelyan/fd-5113-chromium-background-requests

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

M8.52 (FD-5113). Behind its proxy, chromium alone reached seven Google hosts on its own, despite agentenv's managed policies. Now its proxy sees only its pages' requests, but for one Google account check at launch, before it's ready, which nothing tried stops.

On the open web (#588, M8.24) those requests really go out, and #588's per-connection log recorded them beside the agent's own traffic.

What each request was, and what stops it

Found on a VM by running Chrome for Testing 156 with agentenv's flags beside the deployed browser, each copy behind its own copy of the stand-in proxy and writing Chrome's own net log (URLs and traffic annotations), then adding one candidate at a time.

Request (Chrome's own) When Stopped by
update.googleapis.com/service/update2/json (component updater) launch, and 60 s later --component-updater=url-source=file:///dev/null. ComponentUpdatesEnabled: false (already set) leaves it updating the components Chrome exempts from that policy, CRLSets among them; --disable-component-update stops the downloads, but not its checks for two of them
edgedl.me.gvt1.com/…/chrome_component/…crx3 (component downloads, the CRLSet's among them) 60 s the same
safebrowsing.googleapis.com/v5/hashLists:batchGet (Safe Browsing list updates) ~83 s --disable-background-networking, the only one it stops
www.google.com/async/folae?udm=50 (the AI Mode eligibility check) launch --disable-features=AimEnabled; AIModeSettings, GenAiDefaultSettings and GeminiSettings don't stop it
www.google.com (a preconnect to its search engine) launch --disable-features=PreconnectToSearch. NetworkPredictionOptions: 2 stops it too, but also every preconnect and prefetch Chrome makes for pages, which slowed some warm loads on the VM
clients2.google.com/time/1/current (network time) launch BrowserNetworkTimeQueriesEnabled: false
redirector.gvt1.com/…/dict/en-us-10-2.bdic (the spellcheck dictionary for its locale) launch SpellcheckLanguageBlocklist, every language Chromium has a dictionary for. SpellcheckEnabled: false still fetches it, and voids the blocklist
content-autofill.googleapis.com/v1/pages/… (the autofill server's field predictions for a page's forms) a page with forms, such as Google's AutofillAddressEnabled: false and AutofillCreditCardEnabled: false. The AutofillSettings policy already set is inert in this build
accounts.google.com/ListAccounts (a Google account check) launch, before it's ready not stopped: see below

Left: the account check at launch. Its account reconcilor sends it as it starts. None of these stopped it:

  • BrowserSignin: 0 (already set);
  • signin.allowed_on_next_startup: false as an initial preference, which does turn the reconcilor's consistency mode off (Chrome logs "Desktop Identity Consistency disabled") but still sends it;
  • the CookieJarAblation and AvoidAutoTriggerListAccountsOnStale features.

A seeded Preferences doesn't stick: Chrome resets a protected preference it finds there. From a fresh profile the check carries no cookie, it comes before the browser is ready, and it didn't come back in 5 minutes idle or on Google, GitHub, Amazon or Wikipedia.

What changes

The chromium app (browsers/envs/chromium/chromium.py), beside its VERSION pin. They're tuning for this build's own services, not how agentenv runs any website browser (moved from WebsiteBrowserEnvironment in review):

  • QUIET_FLAGS: --disable-background-networking and --component-updater=url-source=file:///dev/null, in its launch command.
  • DISABLED_FEATURES: --disable-features=AimEnabled,PreconnectToSearch, in its launch command.
  • QUIET_POLICIES, its policies over agentenv's: BrowserNetworkTimeQueriesEnabled: false, SpellcheckLanguageBlocklist (SPELLCHECK_LANGUAGES, from Chromium's spellcheck_common.cc), and AutofillAddressEnabled and AutofillCreditCardEnabled: false.
  • A subclass that declares its own launch, as M8.24's chromium-open-web may, keeps QUIET_FLAGS and DISABLED_FEATURES in its command.
  • The proxies: both proxies' failed log lines now carry started, as their connection lines do, so a test can hold a failed request to a time (Greptile's P2).
  • Docs: browsers/README.md.

Decisions I took while you were away, for review

  1. Spellcheck is off in every locale. No policy follows the deploy's locale, because write_policies runs at install. So every language is blocklisted, and a text field shows no squiggles.
  2. Chrome's preloading for pages stays on. The first version set NetworkPredictionOptions: 2 to stop the search engine's preconnect, which also turned off the preconnects and prefetches Chrome makes for pages. PreconnectToSearch replaces it (you chose a, Nov 10).
  3. They live in the chromium app, not the base class (you chose a in review). The base class is unchanged from main.
  4. The issue's second "Done when" is untestable today. It asked for the same result "in a computer with AGENTENV_SITE_PROXY set", but only a computer with no display gets one (sites.browser_environment). A desktop routes its sites by DNS, with no forward proxy, so its browser's own requests reach no proxy log. The desktop's chromium is covered instead:
    • its argv check now pins the new flags;
    • the unit test pins the policies;
    • a headful run on the VM (below) shows the same quiet.
  5. The account check at launch is accepted as the one request left, for the reasons above.

Test plan

  • Unit:

    • test_chromium_app.py:
      • its launch command carries the flags and the disabled features;
      • the policies it writes are agentenv's with its own over them, the blocklist among them;
      • no SpellcheckEnabled and no NetworkPredictionOptions.
    • test_computer_site_proxy.py: both proxies' failed lines carry started.
    • Unit tiers: the protocol tests, tst/unit/env, bundle and cli pass here, apart from the Mac-only Windows disk-recipe test, which fails on main on this Mac too.
  • Integration (CI green on 0ae6e6c, after the move to the chromium app and a merge of main: 32 checks, the remote CodeBuild tier included). One unit shard was rerun for test_computer_queue's timing flake, which this PR doesn't touch and which passes 8 of 8 locally: test_alone_it_makes_no_request_of_its_own_its_proxy_seeing_only_its_page_until_well_after_it_is_ready.

    • The setup: chromium alone; a CDP agent loads a page served on the computer's own loopback, and the test waits until 75 s after the browser is ready.
    • Reading the log: Chromium is then ended, so every connection it held open is logged.
    • The check: the proxy's log holds only that page's host, and an account check started before the browser was ready.
    • On main it fails, listing clients2.google.com, redirector.gvt1.com, www.google.com, edgedl.me.gvt1.com and the rest.
    • The argv checks in chromium_app_test and website_browser_test take the new flags.
  • VM e2e (c6i.4xlarge, amd64, local Docker, Node 22 for the CDP clients), on 0a8d0f5: every integration test of browser_computer_test, chromium_app_test, website_browser_test and browser_gateway_test, 40 passed, 1 skipped (the disk form, no KVM on this VM), in 29 min.

  • Headful, on the VM. In a deployed desktop (Xvfb), the browser agentenv launched carries the new flags. A second headful Chrome with that browser's exact command line, behind a copy of the stand-in proxy, made nothing but the account check at launch in 100 s.

  • VM chaos, one browser computer alone, passed in 11 min. Each phase's connections are told apart by when they started, and Chromium is ended before the log is read:

    Phase Result
    5 minutes idle after it's ready no request
    Its app server killed, so it's launched again (75 s after) no request
    reset_env, a fresh profile and another launch (75 s after) no request; the account check at that launch, the only one in the run
    A CDP agent loads GitHub's login, Amazon, Wikipedia and Google all load; none of the hosts Chrome reached of its own before (update, gvt1.com, clients*.google.com, Safe Browsing, autofill, optimization guide)
    Deployed in fr-FR the account check alone: no spellcheck dictionary for its locale

    The VM is torn down.

  • A real agent arm on the VM, on main and on this branch: Browser Use, with Claude Sonnet 5.5 through LiteLLM, on chromium alone over its CDP address, doing Online-Mind2Web-style tasks on live sites. Each answer was checked against the live page fetched at that moment, so the model couldn't answer from memory; 4 tasks × 4 runs on each:

    Task Right, main / branch Agent's turn, mean s, main / branch Chrome's own hosts per run, main / branch
    Hacker News's top story 4/4 / 4/4 4.25 / 4.0 6 / the account check
    Wikipedia's featured article today 4/4 / 4/4 7.9 / 8.0 6 / the account check
    browser-use's star count on GitHub 4/4 / 4/4 27.8 / 24.6 6 / the account check
    python.org's latest Python 3 release 4/4 / 4/4 5.2 / 5.4 5 / the account check
    • On main, the 5–6 hosts are update.googleapis.com, clients2.google.com, three gvt1.com hosts and accounts.google.com.
    • Plus content-autofill.googleapis.com on every page with a form, in the middle of the agent's own browsing.
    • On 7efcd20 (PreconnectToSearch in place of NetworkPredictionOptions), one more run of each was 4 of 4 right, with the account check alone. The quiet test and both argv checks pass there too.

Not in this PR

  • Chrome's New Tab page in a headful browser. In the headful run above, chrome://newtab/ fetched:

    • www.google.com/async/ddljson (the doodle);
    • www.google.com/complete/s (zero-prefix omnibox suggestions);
    • www.google.com/async/newtab_ogb and its gstatic, ogads-pa and play.google.com/log requests (the Google apps bar).

    It opens only when an agent asks for a new tab (Ctrl+T), and headless opens about:blank instead. NewTabPageLocation: about:blank would stop it, but agents would then see a blank page where a user sees Google's, so that's your call.

🤖 Generated with Claude Code

earakely-scale and others added 2 commits November 10, 2026 00:49
…wn (FD-5113, M8.52)

Behind its proxy, Chrome for Testing 156 alone reached seven Google hosts on
its own despite agentenv's policies. The flags and policies that stop each:

- --disable-background-networking: Safe Browsing's list updates.
- --component-updater=url-source=file:///dev/null: the component updater's
  checks at launch and a minute later, which ComponentUpdatesEnabled leaves on
  for the components Chrome deems critical (CRLSets among them).
- --disable-features=AimEnabled: the AI Mode eligibility check at launch;
  a subclass's own --disable-features is joined to it, since Chromium takes
  only the last one.
- NetworkPredictionOptions 2: the preconnect to its search engine.
- BrowserNetworkTimeQueriesEnabled false: the network time query.
- SpellcheckLanguageBlocklist, every language with a dictionary: the
  dictionary for the deploy's locale (SpellcheckEnabled false still fetches it).
- AutofillAddressEnabled and AutofillCreditCardEnabled false: the autofill
  server's field predictions for a page's forms.

One request is left, a Google account check at launch, before the browser is
ready, which nothing tried stops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ktop's background requests

A desktop routes its sites by DNS, with no forward proxy, so its browser's own
requests never reach a proxy log; the desktop's flags are pinned by its argv
check and its policies by the unit test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale marked this pull request as ready for review November 10, 2026 16:06
@earakely-scale
earakely-scale requested a review from a team as a code owner November 10, 2026 16:06
@earakely-scale

Copy link
Copy Markdown
Collaborator Author

@greptileai review

earakely-scale and others added 4 commits November 10, 2026 08:49
The quiet test exempted every failed request to the account check host from
its time check, since a failed line had no start, so a host Chrome kept
retrying after it was ready would pass unseen. Both proxies' failed lines now
carry started, and the test holds every request of its own to before the
browser was ready.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e, not NetworkPredictionOptions

NetworkPredictionOptions 2 stopped the preconnect to the search engine at
launch, but also every preconnect and prefetch Chrome makes for pages, which
cost warm loads on a VM. --disable-features=PreconnectToSearch stops just the
launch preconnect, so pages load as they do for a user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hromium app

They're tuning for one build's own services, found against Chrome for
Testing 156, not how agentenv runs any website browser: the feature names and
the spellcheck languages may not exist in another Chromium build, and they
need checking again whenever chromium's VERSION moves. So QUIET_FLAGS,
DISABLED_FEATURES and QUIET_POLICIES move from WebsiteBrowserEnvironment to
the chromium app, its launch command and its policies, beside VERSION, and
the base class is back as it was, its --disable-features merge with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale earakely-scale changed the title feat(website-browser): chromium makes no background requests of its own (FD-5113, M8.52) feat(browsers): chromium makes no background requests of its own (FD-5113, M8.52) Nov 10, 2026
@earakely-scale
earakely-scale merged commit cfb5d65 into main Nov 10, 2026
60 of 63 checks passed
@earakely-scale
earakely-scale deleted the edgararakelyan/fd-5113-chromium-background-requests branch November 10, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant