fix(core): avoid keep-alive socket reuse during OAuth token exchange#28103
fix(core): avoid keep-alive socket reuse during OAuth token exchange#28103ryium wants to merge 1 commit into
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical regression in Node.js versions 24.17.0 and later, where socket reuse in the global http.Agent causes OAuth token exchange failures. By forcing a fresh connection per request via a custom https.Agent when no proxy is configured, the fix restores login functionality for users on newer Node.js versions while maintaining support for existing proxy environments. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
📊 PR Size: size/M
|
There was a problem hiding this comment.
Code Review
This pull request introduces a workaround for a Node.js regression (nodejs/node#63989) where socket reuse in http.Agent causes node-fetch to throw a spurious ERR_STREAM_PREMATURE_CLOSE error during OAuth token exchange. To resolve this, HTTP keep-alive is disabled by configuring a custom https.Agent with keepAlive: false when initializing the OAuth2Client, unless a proxy is configured. Corresponding unit tests have been added to verify this behavior under both proxy and non-proxy configurations. There are no review comments, so I have no feedback to provide.
7a5a576 to
cbab0dd
Compare
Summary
OAuth "Sign in with Google" fails with
Failed to exchange authorization code for tokens: ... Premature closeon thethree Node.js releases that shipped the June 2026 security fix for
CVE-2026-48931 ("fix response queue poisoning in
http.Agent"):24.17.0, 22.23.0, and 26.3.1. That fix regressed keep-alive socket reuse,
making
node-fetchthrow a spuriousERR_STREAM_PREMATURE_CLOSEwhen a pooledsocket is reused, breaking login. Each release is fixed in its next version
(24.18.0 / 22.23.1 / 26.x), but users pinned to an affected release (e.g. a
node:24.17.0base image) still hit it. This change makes the OAuth tokenexchange use a fresh (non-keep-alive) connection so sign-in works regardless of
the running Node version.
Details
The token exchange runs through
google-auth-library→gaxios→node-fetch,which uses Node's global keep-alive agent. The CVE-2026-48931 fix attaches a
guard listener to idle pooled sockets; on reuse,
node-fetch@2misreads this asa premature close and throws
ERR_STREAM_PREMATURE_CLOSE(see nodejs/node#63989).The Node-side regression is fixed by nodejs/node#64004, shipped in
24.18.0 / 22.23.1 / 26.x.
Affected vs. unaffected (verified empirically with
mise,node-fetch@2over akeep-alive agent reusing a single socket):
24.17.0,22.23.0ERR_STREAM_PREMATURE_CLOSEon first reuse24.18.0,22.23.124.13.0,20.17.0(pre-fix / never patched)Fix: in
initOauthClient(packages/core/src/code_assist/oauth2.ts), passnew https.Agent({ keepAlive: false })to theOAuth2Clienttransporter when noproxy is configured, forcing a fresh connection per request and sidestepping the
regression on any Node version. It is harmless on fixed/unaffected versions
because the OAuth token exchange is a one-shot request that gains nothing from
keep-alive. The proxy path is left unchanged, since supplying our own agent would
make gaxios ignore the configured proxy. Because the same client also backs the
Code Assist API calls, the whole code-assist flow benefits.
Related Issues
How to Validate
(
node -v). On 24.18.0 / 22.23.1 / 26.x the bug no longer reproduces withoutthis change.
npm run generate && npm run build --workspace=@google/gemini-cli-core.npx vitest run packages/core/src/code_assist/oauth2.test.tskeepAlive: falseagent whenno proxy is set, and keeps
proxy(no custom agent) when a proxy is set.authorization-code → token exchange completes instead of failing with
"Premature close".
HTTPS_PROXYset /--proxyconfigured, login stillroutes through the proxy as before.
Pre-Merge Checklist