diff --git a/src/infra/net/proxy-env.test.ts b/src/infra/net/proxy-env.test.ts index 1ceeae0a354..1056d81cd3e 100644 --- a/src/infra/net/proxy-env.test.ts +++ b/src/infra/net/proxy-env.test.ts @@ -293,6 +293,12 @@ describe("matchesNoProxy", () => { env: { NO_PROXY: "[::1]:8080" } as NodeJS.ProcessEnv, expected: true, }, + { + name: "matches bare IPv6 literal", + url: "http://[::1]:8080/health", + env: { NO_PROXY: "::1" } as NodeJS.ProcessEnv, + expected: true, + }, { name: "matches IPv4 CIDR entries", url: "http://100.64.0.3:8990/v1/messages", @@ -387,6 +393,15 @@ describe("shouldUseEnvHttpProxyForUrl", () => { } as NodeJS.ProcessEnv, expected: false, }, + { + name: "keeps strict mode for bare IPv6 NO_PROXY matches", + url: "http://[::1]:11434/v1", + env: { + HTTP_PROXY: "http://proxy.test:8080", + NO_PROXY: "::1", + } as NodeJS.ProcessEnv, + expected: false, + }, { name: "keeps strict mode for non-http URLs", url: "file:///tmp/input.txt", diff --git a/src/infra/net/proxy-env.ts b/src/infra/net/proxy-env.ts index 330d030f41a..bbdc4cd2732 100644 --- a/src/infra/net/proxy-env.ts +++ b/src/infra/net/proxy-env.ts @@ -127,7 +127,7 @@ export function shouldUseEnvHttpProxyForUrl( * matches (kept in sync with that behavior) * - Subdomain suffix match (`openai.com` matches `api.openai.com`) * - Optional `:port` suffix; when present, must match target port - * - IPv6 literals in bracketed form (`[::1]`) + * - IPv6 literals in bracketed (`[::1]`) or bare (`::1`) form * - OpenClaw extension: IPv4 CIDR and octet-wildcard entries * (`100.64.0.0/10`, `100.64.*`) bypass the trusted env proxy mode before * undici's EnvHttpProxyAgent is selected. @@ -187,10 +187,15 @@ export function matchesNoProxy(targetUrl: string, env: NodeJS.ProcessEnv = proce entryHost = m[1]; entryPort = m[2]; } else { - const colonIdx = entry.lastIndexOf(":"); - if (colonIdx > 0 && /^\d+$/.test(entry.slice(colonIdx + 1))) { - entryHost = entry.slice(0, colonIdx); - entryPort = entry.slice(colonIdx + 1); + const firstColonIdx = entry.indexOf(":"); + const lastColonIdx = entry.lastIndexOf(":"); + if ( + firstColonIdx > -1 && + firstColonIdx === lastColonIdx && + /^\d+$/.test(entry.slice(lastColonIdx + 1)) + ) { + entryHost = entry.slice(0, lastColonIdx); + entryPort = entry.slice(lastColonIdx + 1); } else { entryHost = entry; }