Skip to content

fix(googlechat): harden google auth transport#69812

Merged
vincentkoc merged 17 commits into
mainfrom
investigate-npm-deprecations
Apr 22, 2026
Merged

fix(googlechat): harden google auth transport#69812
vincentkoc merged 17 commits into
mainfrom
investigate-npm-deprecations

Conversation

@vincentkoc

Copy link
Copy Markdown
Member

summary

  • move the gaxios fetch compat shim out of the root CLI path and into Google Chat auth
  • remove the dead root gaxios dependency and startup hook
  • stage Google Chat runtime dependencies so the channel owns its own Google auth runtime

why

The root package was still carrying a legacy gaxios compat path even though the only remaining in-repo caller was Google Chat auth. Keeping that shim and dependency at the root made the install graph noisier than it needed to be and kept startup behavior coupled to a plugin-local concern.

This PR localizes that behavior to extensions/googlechat and keeps the plugin runtime self-contained.

impact

  • root CLI startup no longer patches gaxios globally
  • Google Chat still installs the compat shim before loading google-auth-library
  • root no longer declares gaxios directly

follow-up

This does not remove the remaining node-domexception deprecation warning from npm install. That warning still comes from the broader dependency chain below and should be handled in a separate PR:

  • @mariozechner/pi-ai -> @google/genai -> google-auth-library -> gaxios -> node-fetch -> fetch-blob -> node-domexception

I think that belongs in a follow-up PR, not this one. @mariozechner/pi-ai is used across core/provider runtime paths, so mixing that dependency work into this scoped cleanup would balloon the blast radius.

validation

  • pnpm test extensions/googlechat/src/gaxios-fetch-compat.test.ts extensions/googlechat/src/targets.test.ts src/index.test.ts src/plugins/contracts/package-manifest.contract.test.ts test/scripts/root-dependency-ownership-audit.test.ts

  • attempted full staged check:changed, but this worktree currently has unrelated missing-workspace-file failures in ui/ and packages/plugin-package-contract/ paths

@vincentkoc vincentkoc self-assigned this Apr 21, 2026
@openclaw-barnacle openclaw-barnacle Bot added channel: googlechat Channel integration: googlechat size: S maintainer Maintainer-authored PR labels Apr 21, 2026
@greptile-apps

greptile-apps Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR localizes the gaxios fetch-compat shim from the root CLI startup path into extensions/googlechat, removes the now-dead root-level gaxios dependency, and enables stageRuntimeDependencies on the googlechat bundle so the plugin owns its own Google Auth runtime. The refactoring is straightforward and well-contained — the shim logic itself is unchanged, and the new test file exercises the three key paths (native fetch patching, legacy window shim fallback, and proxy-agent dispatcher translation).

Confidence Score: 5/5

Safe to merge — clean scoped refactoring with no behavioral changes to the shim logic.

All remaining findings are P2 or lower. The shim handles missing gaxios gracefully, the concurrent-call guard is correct given JavaScript's single-threaded event loop, and undici is transitively available through the required openclaw peer dependency. No P0/P1 issues found.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(googlechat): localize google auth ga..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60c781d141

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/googlechat/package.json

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3269ccfde5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/googlechat/package.json
@vincentkoc vincentkoc changed the title fix(googlechat): localize google auth gaxios compat fix(googlechat): harden google auth transport Apr 21, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab73fb502f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/googlechat/src/google-auth.runtime.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4582811c1e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/googlechat/src/google-auth.runtime.ts Outdated
@vincentkoc
vincentkoc force-pushed the investigate-npm-deprecations branch 2 times, most recently from 032b826 to 6dd5292 Compare April 21, 2026 21:16
@vincentkoc
vincentkoc force-pushed the investigate-npm-deprecations branch from a3c626b to 85d3ba3 Compare April 21, 2026 21:36
@aisle-research-bot

aisle-research-bot Bot commented Apr 21, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 2 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Client TLS certificate/key may be sent to proxy in env-proxy mode (credential leakage)
2 🟡 Medium Potential memory exhaustion when reading Google Chat service account credentials file
1. 🟡 Client TLS certificate/key may be sent to proxy in env-proxy mode (credential leakage)
Property Value
Severity Medium
CWE CWE-522
Location extensions/googlechat/src/google-auth.runtime.ts:354-384

Description

resolveGoogleAuthDispatcherPolicy() derives TLS credentials (cert/key) from the incoming gaxios request init (init.cert, init.key, or init.agent shapes) and then attaches them as proxyTls not only for explicit proxies but also when a proxy is picked up implicitly from HTTP(S)_PROXY (env-proxy mode).

This can leak mTLS credentials to an unintended proxy:

  • Input: cert/key can be provided per request via gaxios/google-auth-library (init.cert, init.key, or init.agent.options/connectOpts).
  • Proxy selection: when HTTP_PROXY/HTTPS_PROXY is set and NO_PROXY does not match, the code chooses mode: "env-proxy".
  • Sink: the derived tlsOptions are forwarded as dispatcherPolicy.proxyTls, which (by design) configures the TLS settings for the proxy connection, not the destination.

If an attacker can influence environment proxy settings (common in some deployment setups) or if a proxy is misconfigured, the client certificate/private key intended for the Google endpoint could be presented to that proxy, disclosing credentials and enabling impersonation.

Vulnerable code:

if (envProxyUrl) {
  return {
    dispatcherPolicy: {
      mode: "env-proxy",
      ...(hasTlsOptions(tlsOptions) ? { proxyTls: { ...tlsOptions } } : {}),
    },
    init: nextInit,
  };
}

Recommendation

Do not automatically reuse destination TLS credentials as proxy TLS credentials.

  • Only set proxyTls when the proxy configuration explicitly provides TLS options intended for the proxy (e.g., via a dedicated proxyTls field or a proxy-agent-specific config), not when TLS is derived from generic cert/key/agent options.
  • For env-proxy mode, default to no proxyTls unless explicitly configured.

Example safer change:

if (envProxyUrl) {
  return {
    dispatcherPolicy: {
      mode: "env-proxy",// Do not forward destination mTLS credentials to the proxy.
    },
    init: nextInit,
  };
}// Only apply connect TLS options for direct connections.
if (hasTlsOptions(tlsOptions)) {
  return {
    dispatcherPolicy: { mode: "direct", connect: { ...tlsOptions } },
    init: nextInit,
  };
}

If proxy mTLS is required, introduce a separate, explicit configuration path (and keep it distinct from destination TLS settings).

2. 🟡 Potential memory exhaustion when reading Google Chat service account credentials file
Property Value
Severity Medium
CWE CWE-400
Location extensions/googlechat/src/google-auth.runtime.ts:288-308

Description

The readCredentialsFile() helper reads a configured service account JSON file using FileHandle.readFile(), which buffers the entire file contents into memory before enforcing the size limit.

  • Input: account.credentialsFile is sourced from configuration (serviceAccountFile) or environment variable (GOOGLE_CHAT_SERVICE_ACCOUNT_FILE).
  • Guard: the code checks stat.isFile() and stat.size before reading, but on some pseudo-filesystems (e.g., certain /proc entries) stat.size may be reported as 0/unknown while reads can yield very large data.
  • Sink: await handle.readFile({ encoding: "utf8" }) can therefore allocate an unbounded string, leading to process OOM / denial-of-service, and only afterwards checks Buffer.byteLength(raw).

Vulnerable code:

const stat = await handle.stat();
if (stat.size > MAX_GOOGLE_CHAT_SERVICE_ACCOUNT_FILE_BYTES) { /* ... */ }

raw = await handle.readFile({ encoding: "utf8" });
if (Buffer.byteLength(raw, "utf8") > MAX_GOOGLE_CHAT_SERVICE_ACCOUNT_FILE_BYTES) { /* ... */ }

Recommendation

Avoid unbounded buffering when reading a path that may point to special files.

  • Prefer streaming reads with a hard cap (read up to MAX_GOOGLE_CHAT_SERVICE_ACCOUNT_FILE_BYTES + 1 bytes and then abort).
  • Optionally also reject paths under known pseudo-filesystem prefixes on Linux (/proc, /sys, /dev) if that fits your threat model.

Example (cap read size):

import fs from "node:fs";
import { once } from "node:events";

async function readFileCapped(path: string, maxBytes: number): Promise<string> {
  const stream = fs.createReadStream(path, { encoding: "utf8" });
  let data = "";
  let total = 0;
  return await new Promise((resolve, reject) => {
    stream.on("data", (chunk: string) => {
      total += Buffer.byteLength(chunk, "utf8");
      if (total > maxBytes) {
        stream.destroy(new Error(`File exceeds ${maxBytes} bytes`));
        return;
      }
      data += chunk;
    });
    stream.on("error", reject);
    stream.on("end", () => resolve(data));
  });
}// usage:
const raw = await readFileCapped(resolvedPath, MAX_GOOGLE_CHAT_SERVICE_ACCOUNT_FILE_BYTES);

This prevents large/unknown-sized special files from causing OOM before the limit check runs.


Analyzed PR: #69812 at commit 8c093f7

Last updated on: 2026-04-22T05:42:32Z

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ebad02e79

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +132 to +135
const httpsProxy =
lowerHttpsProxy !== undefined
? lowerHttpsProxy
: normalizeGoogleAuthProxyEnvValue(process.env.HTTPS_PROXY);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor gaxios proxy env precedence for Google auth requests

resolveGoogleAuthEnvProxyUrl currently prefers lowercase env vars (https_proxy/http_proxy) whenever they are set, so a stale lowercase value will override HTTPS_PROXY/HTTP_PROXY. This diverges from gaxios’ own precedence (and the previous compat path), which checks uppercase first. In environments that export both forms with different values, Google Chat auth can be routed through the wrong proxy or fail unexpectedly; the helper should match gaxios ordering to avoid this regression.

Useful? React with 👍 / 👎.

@vincentkoc
vincentkoc merged commit 6d6845e into main Apr 22, 2026
127 checks passed
@vincentkoc
vincentkoc deleted the investigate-npm-deprecations branch April 22, 2026 05:40
medikoo pushed a commit to medikoo/openclaw that referenced this pull request Apr 24, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request May 7, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
* fix(googlechat): localize google auth gaxios compat

* fix(googlechat): declare undici for staged runtime deps

* fix(googlechat): harden google auth transport

* fix(googlechat): narrow credential file reads

* fix(googlechat): preserve auth proxy transport

* fix(googlechat): allow symlinked auth files

* fix(googlechat): atomically load auth files

* fix(googlechat): eagerly buffer auth responses

* fix(googlechat): cap auth response buffering

* fix(googlechat): pin staged auth runtime deps

* fix(googlechat): buffer auth responses as array buffers

* Update CHANGELOG.md

* fix(googlechat): reject unstreamed auth responses

* fix(googlechat): use ambient fetch for auth transport

* fix(googlechat): keep guarded auth fetch on runtime path

* fix(googlechat): align staged zod range

* chore(lockfile): sync googlechat zod spec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: googlechat Channel integration: googlechat maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant