Skip to content

Commit f408bba

Browse files
DhtIsCodingDhtsteipete
authored
fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode for remote embeddings in proxy environments (#71506)
* fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode in withRemoteHttpResponse When a HTTP/HTTPS proxy is configured via environment variables (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY), the withRemoteHttpResponse function now passes mode=TRUSTED_ENV_PROXY to fetchWithSsrFGuard. This causes DNS resolution to skip the local resolver and route through the configured proxy, fixing 'fetch failed' errors for remote memory embeddings (including GitHub Copilot embeddings) in proxy environments (e.g. Clash TUN, corporate proxies). Previously, without an explicit mode, fetchWithSsrFGuard defaulted to STRICT mode which performs local DNS pre-resolution via resolvePinnedHostnameWithPolicy(), failing in proxy environments where DNS must go through the proxy. Fixes: #52162 * fix: harden memory env proxy guard (#71506) (thanks @DhtIsCoding) --------- Co-authored-by: Dht <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
1 parent f1470b5 commit f408bba

11 files changed

Lines changed: 294 additions & 51 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai
2020

2121
### Fixes
2222

23+
- Memory-host SDK: use trusted env-proxy mode for remote embedding and batch HTTP calls only when Undici will proxy that target, preserving SSRF DNS pinning for `ALL_PROXY`-only and `NO_PROXY` bypass cases. Fixes #52162. (#71506) Thanks @DhtIsCoding.
2324
- Gateway/dashboard: render Control UI and WebSocket links with `https://`/`wss://` when `gateway.tls.enabled=true`, including `openclaw gateway status`. Fixes #71494. (#71499) Thanks @deepkilo.
2425
- Agents/OpenAI-compatible: default proxy/local completions tool requests to `tool_choice: "auto"` when tools are present, so providers enter native tool-calling mode instead of replying with plain-text tool directives. (#71472) Thanks @Speed-maker.
2526
- OpenAI image generation: use `gpt-5.5` for the Codex OAuth responses transport instead of the retired `gpt-5.4` model, fixing 500s from ChatGPT Codex image generation. Fixes #71513. Thanks @baolongl.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({
4+
fetchWithSsrFGuardMock: vi.fn(),
5+
shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false),
6+
}));
7+
8+
vi.mock("../../../../src/infra/net/fetch-guard.js", async () => {
9+
const actual = await vi.importActual<typeof import("../../../../src/infra/net/fetch-guard.js")>(
10+
"../../../../src/infra/net/fetch-guard.js",
11+
);
12+
return {
13+
...actual,
14+
fetchWithSsrFGuard: fetchWithSsrFGuardMock,
15+
};
16+
});
17+
18+
vi.mock("../../../../src/infra/net/proxy-env.js", async () => {
19+
const actual = await vi.importActual<typeof import("../../../../src/infra/net/proxy-env.js")>(
20+
"../../../../src/infra/net/proxy-env.js",
21+
);
22+
return {
23+
...actual,
24+
shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock,
25+
};
26+
});
27+
28+
import { GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js";
29+
import { withRemoteHttpResponse } from "./remote-http.js";
30+
31+
describe("package withRemoteHttpResponse", () => {
32+
beforeEach(() => {
33+
vi.clearAllMocks();
34+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
35+
fetchWithSsrFGuardMock.mockResolvedValue({
36+
response: new Response("ok", { status: 200 }),
37+
finalUrl: "https://memory.example/v1",
38+
release: vi.fn(async () => {}),
39+
});
40+
});
41+
42+
it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => {
43+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
44+
45+
await withRemoteHttpResponse({
46+
url: "https://memory.example/v1/embeddings",
47+
onResponse: async () => undefined,
48+
});
49+
50+
expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith(
51+
expect.objectContaining({
52+
url: "https://memory.example/v1/embeddings",
53+
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
54+
}),
55+
);
56+
});
57+
58+
it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => {
59+
await withRemoteHttpResponse({
60+
url: "https://internal.corp.example/v1/embeddings",
61+
onResponse: async () => undefined,
62+
});
63+
64+
const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0];
65+
expect(call).toBeDefined();
66+
expect(call).not.toHaveProperty("mode");
67+
});
68+
});

packages/memory-host-sdk/src/host/remote-http.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { fetchWithSsrFGuard } from "../../../../src/infra/net/fetch-guard.js";
1+
import { fetchWithSsrFGuard, GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js";
2+
import { shouldUseEnvHttpProxyForUrl } from "../../../../src/infra/net/proxy-env.js";
23
import type { SsrFPolicy } from "../../../../src/infra/net/ssrf.js";
34

45
export function buildRemoteBaseUrlPolicy(baseUrl: string): SsrFPolicy | undefined {
@@ -31,6 +32,9 @@ export async function withRemoteHttpResponse<T>(params: {
3132
init: params.init,
3233
policy: params.ssrfPolicy,
3334
auditContext: params.auditContext ?? "memory-remote",
35+
...(shouldUseEnvHttpProxyForUrl(params.url)
36+
? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY }
37+
: {}),
3438
});
3539
try {
3640
return await params.onResponse(response);

src/infra/net/fetch-guard.ssrf.test.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ describe("fetchWithSsrFGuard hardening", () => {
133133
expectEnvProxy: boolean;
134134
}): Promise<void> {
135135
clearProxyEnv();
136-
vi.stubEnv("HTTP_PROXY", "http://127.0.0.1:7890");
136+
vi.stubEnv("http_proxy", "http://127.0.0.1:7890");
137137
(globalThis as Record<string, unknown>)[TEST_UNDICI_RUNTIME_DEPS_KEY] = {
138138
Agent: agentCtor,
139139
EnvHttpProxyAgent: envHttpProxyAgentCtor,
@@ -1018,6 +1018,57 @@ describe("fetchWithSsrFGuard hardening", () => {
10181018
});
10191019
});
10201020

1021+
it("keeps DNS pinning in trusted proxy mode when only ALL_PROXY is configured", async () => {
1022+
clearProxyEnv();
1023+
vi.stubEnv("ALL_PROXY", "http://127.0.0.1:7890");
1024+
(globalThis as Record<string, unknown>)[TEST_UNDICI_RUNTIME_DEPS_KEY] = {
1025+
Agent: agentCtor,
1026+
EnvHttpProxyAgent: envHttpProxyAgentCtor,
1027+
ProxyAgent: proxyAgentCtor,
1028+
fetch: vi.fn(async () => okResponse()),
1029+
};
1030+
const lookupFn = createPublicLookup();
1031+
const fetchImpl = vi.fn(async () => okResponse());
1032+
1033+
const result = await fetchWithSsrFGuard({
1034+
url: "https://public.example/resource",
1035+
fetchImpl,
1036+
lookupFn,
1037+
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
1038+
});
1039+
1040+
expect(envHttpProxyAgentCtor).not.toHaveBeenCalled();
1041+
expect(agentCtor).toHaveBeenCalled();
1042+
expect(lookupFn).toHaveBeenCalledWith("public.example", { all: true });
1043+
await result.release();
1044+
});
1045+
1046+
it("keeps DNS pinning in trusted proxy mode for NO_PROXY targets", async () => {
1047+
clearProxyEnv();
1048+
vi.stubEnv("HTTPS_PROXY", "http://127.0.0.1:7890");
1049+
vi.stubEnv("NO_PROXY", "public.example");
1050+
(globalThis as Record<string, unknown>)[TEST_UNDICI_RUNTIME_DEPS_KEY] = {
1051+
Agent: agentCtor,
1052+
EnvHttpProxyAgent: envHttpProxyAgentCtor,
1053+
ProxyAgent: proxyAgentCtor,
1054+
fetch: vi.fn(async () => okResponse()),
1055+
};
1056+
const lookupFn = createPublicLookup();
1057+
const fetchImpl = vi.fn(async () => okResponse());
1058+
1059+
const result = await fetchWithSsrFGuard({
1060+
url: "https://public.example/resource",
1061+
fetchImpl,
1062+
lookupFn,
1063+
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
1064+
});
1065+
1066+
expect(envHttpProxyAgentCtor).not.toHaveBeenCalled();
1067+
expect(agentCtor).toHaveBeenCalled();
1068+
expect(lookupFn).toHaveBeenCalledWith("public.example", { all: true });
1069+
await result.release();
1070+
});
1071+
10211072
it("applies explicit timeoutMs to guarded direct dispatchers", async () => {
10221073
(globalThis as Record<string, unknown>)[TEST_UNDICI_RUNTIME_DEPS_KEY] = {
10231074
Agent: agentCtor,

src/infra/net/fetch-guard.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Dispatcher } from "undici";
22
import { logWarn } from "../../logger.js";
33
import { captureHttpExchange } from "../../proxy-capture/runtime.js";
44
import { buildTimeoutAbortSignal } from "../../utils/fetch-timeout.js";
5-
import { hasProxyEnvConfigured } from "./proxy-env.js";
5+
import { shouldUseEnvHttpProxyForUrl } from "./proxy-env.js";
66
import { retainSafeHeadersForCrossOriginRedirect as retainSafeRedirectHeaders } from "./redirect-headers.js";
77
import {
88
fetchWithRuntimeDispatcher,
@@ -355,7 +355,8 @@ export async function fetchWithSsrFGuard(params: GuardedFetchOptions): Promise<G
355355
);
356356
await assertExplicitProxyAllowed(params.dispatcherPolicy, params.lookupFn, params.policy);
357357
const canUseTrustedEnvProxy =
358-
mode === GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY && hasProxyEnvConfigured();
358+
mode === GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY &&
359+
shouldUseEnvHttpProxyForUrl(parsedUrl.toString());
359360
const timeoutMs = resolveDispatcherTimeoutMs(params.timeoutMs);
360361
if (canUseTrustedEnvProxy) {
361362
dispatcher = createHttp1EnvHttpProxyAgent(undefined, timeoutMs);

src/infra/net/proxy-env.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
hasProxyEnvConfigured,
55
matchesNoProxy,
66
resolveEnvHttpProxyUrl,
7+
shouldUseEnvHttpProxyForUrl,
78
} from "./proxy-env.js";
89

910
describe("hasProxyEnvConfigured", () => {
@@ -233,3 +234,55 @@ describe("matchesNoProxy", () => {
233234
expect(matchesNoProxy(url, env)).toBe(expected);
234235
});
235236
});
237+
238+
describe("shouldUseEnvHttpProxyForUrl", () => {
239+
it.each([
240+
{
241+
name: "uses HTTPS_PROXY for https URLs",
242+
url: "https://api.example.com/v1",
243+
env: { HTTPS_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
244+
expected: true,
245+
},
246+
{
247+
name: "falls back to HTTP_PROXY for https URLs",
248+
url: "https://api.example.com/v1",
249+
env: { HTTP_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
250+
expected: true,
251+
},
252+
{
253+
name: "uses HTTP_PROXY for http URLs",
254+
url: "http://api.example.com/v1",
255+
env: { HTTP_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
256+
expected: true,
257+
},
258+
{
259+
name: "ignores ALL_PROXY-only environments",
260+
url: "https://api.example.com/v1",
261+
env: { ALL_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
262+
expected: false,
263+
},
264+
{
265+
name: "keeps strict mode for NO_PROXY matches",
266+
url: "https://internal.corp.example/v1",
267+
env: {
268+
HTTPS_PROXY: "http://proxy.test:8080",
269+
NO_PROXY: "corp.example",
270+
} as NodeJS.ProcessEnv,
271+
expected: false,
272+
},
273+
{
274+
name: "keeps strict mode for non-http URLs",
275+
url: "file:///tmp/input.txt",
276+
env: { HTTPS_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
277+
expected: false,
278+
},
279+
{
280+
name: "keeps strict mode for malformed URLs",
281+
url: "not-a-url",
282+
env: { HTTPS_PROXY: "http://proxy.test:8080" } as NodeJS.ProcessEnv,
283+
expected: false,
284+
},
285+
])("$name", ({ url, env, expected }) => {
286+
expect(shouldUseEnvHttpProxyForUrl(url, env)).toBe(expected);
287+
});
288+
});

src/infra/net/proxy-env.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,27 @@ export function hasEnvHttpProxyConfigured(
5454
return resolveEnvHttpProxyUrl(protocol, env) !== undefined;
5555
}
5656

57+
export function shouldUseEnvHttpProxyForUrl(
58+
targetUrl: string,
59+
env: NodeJS.ProcessEnv = process.env,
60+
): boolean {
61+
let protocol: "http" | "https";
62+
try {
63+
const parsed = new URL(targetUrl);
64+
if (parsed.protocol === "http:") {
65+
protocol = "http";
66+
} else if (parsed.protocol === "https:") {
67+
protocol = "https";
68+
} else {
69+
return false;
70+
}
71+
} catch {
72+
return false;
73+
}
74+
75+
return hasEnvHttpProxyConfigured(protocol, env) && !matchesNoProxy(targetUrl, env);
76+
}
77+
5778
/**
5879
* Check whether a target URL should bypass the HTTP proxy per NO_PROXY env var.
5980
*

src/media-understanding/shared.test.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
22

3-
const { fetchWithSsrFGuardMock, hasEnvHttpProxyConfiguredMock, matchesNoProxyMock } = vi.hoisted(
4-
() => ({
5-
fetchWithSsrFGuardMock: vi.fn(),
6-
hasEnvHttpProxyConfiguredMock: vi.fn(() => false),
7-
matchesNoProxyMock: vi.fn(() => false),
8-
}),
9-
);
3+
const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({
4+
fetchWithSsrFGuardMock: vi.fn(),
5+
shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false),
6+
}));
107

118
vi.mock("../infra/net/fetch-guard.js", async () => {
129
const actual = await vi.importActual<typeof import("../infra/net/fetch-guard.js")>(
@@ -24,8 +21,7 @@ vi.mock("../infra/net/proxy-env.js", async () => {
2421
);
2522
return {
2623
...actual,
27-
hasEnvHttpProxyConfigured: hasEnvHttpProxyConfiguredMock,
28-
matchesNoProxy: matchesNoProxyMock,
24+
shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock,
2925
};
3026
});
3127

@@ -42,8 +38,7 @@ import {
4238
} from "./shared.js";
4339

4440
beforeEach(() => {
45-
hasEnvHttpProxyConfiguredMock.mockReturnValue(false);
46-
matchesNoProxyMock.mockReturnValue(false);
41+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
4742
});
4843

4944
afterEach(() => {
@@ -417,7 +412,7 @@ describe("fetchWithTimeoutGuarded", () => {
417412
});
418413

419414
it("does not set a guarded fetch mode when no HTTP proxy env is configured", async () => {
420-
hasEnvHttpProxyConfiguredMock.mockReturnValue(false);
415+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
421416
fetchWithSsrFGuardMock.mockResolvedValue({
422417
response: new Response(null, { status: 200 }),
423418
finalUrl: "https://example.com",
@@ -432,7 +427,7 @@ describe("fetchWithTimeoutGuarded", () => {
432427
});
433428

434429
it("auto-selects trusted env proxy mode when HTTP proxy env is configured", async () => {
435-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
430+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
436431
fetchWithSsrFGuardMock.mockResolvedValue({
437432
response: new Response(null, { status: 200 }),
438433
finalUrl: "https://api.minimax.io",
@@ -454,7 +449,7 @@ describe("fetchWithTimeoutGuarded", () => {
454449
});
455450

456451
it("respects an explicit mode from the caller when HTTP proxy env is configured", async () => {
457-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
452+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
458453
fetchWithSsrFGuardMock.mockResolvedValue({
459454
response: new Response(null, { status: 200 }),
460455
finalUrl: "https://api.example.com",
@@ -473,7 +468,7 @@ describe("fetchWithTimeoutGuarded", () => {
473468
});
474469

475470
it("auto-upgrades transcription requests to trusted env proxy when proxy env is configured", async () => {
476-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
471+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
477472
fetchWithSsrFGuardMock.mockResolvedValue({
478473
response: new Response(null, { status: 200 }),
479474
finalUrl: "https://api.openai.com",
@@ -495,7 +490,7 @@ describe("fetchWithTimeoutGuarded", () => {
495490
});
496491

497492
it("forwards an explicit mode override through postJsonRequest even when proxy env is configured", async () => {
498-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
493+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
499494
fetchWithSsrFGuardMock.mockResolvedValue({
500495
response: new Response(null, { status: 200 }),
501496
finalUrl: "https://api.example.com",
@@ -518,7 +513,7 @@ describe("fetchWithTimeoutGuarded", () => {
518513
});
519514

520515
it("forwards an explicit mode override through postTranscriptionRequest even when proxy env is configured", async () => {
521-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
516+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
522517
fetchWithSsrFGuardMock.mockResolvedValue({
523518
response: new Response(null, { status: 200 }),
524519
finalUrl: "https://api.example.com",
@@ -541,11 +536,11 @@ describe("fetchWithTimeoutGuarded", () => {
541536
});
542537

543538
it("does not auto-upgrade when only ALL_PROXY is configured (HTTP(S) proxy gate)", async () => {
544-
// ALL_PROXY is ignored by EnvHttpProxyAgent; `hasEnvHttpProxyConfigured`
539+
// ALL_PROXY is ignored by EnvHttpProxyAgent; the shared proxy URL helper
545540
// reflects that by returning false when only ALL_PROXY is set. Auto-upgrade
546541
// must NOT fire, otherwise the request would skip pinned-DNS/SSRF checks
547542
// and then be dispatched directly.
548-
hasEnvHttpProxyConfiguredMock.mockReturnValue(false);
543+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
549544
fetchWithSsrFGuardMock.mockResolvedValue({
550545
response: new Response(null, { status: 200 }),
551546
finalUrl: "https://api.example.com",
@@ -568,7 +563,7 @@ describe("fetchWithTimeoutGuarded", () => {
568563
// Callers with custom proxy URL / proxyTls / connect options must keep
569564
// control over the dispatcher. Auto-upgrade would build an
570565
// EnvHttpProxyAgent that silently drops those overrides.
571-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
566+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
572567
fetchWithSsrFGuardMock.mockResolvedValue({
573568
response: new Response(null, { status: 200 }),
574569
finalUrl: "https://api.example.com",
@@ -595,8 +590,7 @@ describe("fetchWithTimeoutGuarded", () => {
595590
// for NO_PROXY matches, but in TRUSTED_ENV_PROXY mode fetchWithSsrFGuard
596591
// skips pinned-DNS checks — so auto-upgrading those targets would bypass
597592
// SSRF protection. Keep strict mode for NO_PROXY matches.
598-
hasEnvHttpProxyConfiguredMock.mockReturnValue(true);
599-
matchesNoProxyMock.mockReturnValue(true);
593+
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
600594
fetchWithSsrFGuardMock.mockResolvedValue({
601595
response: new Response(null, { status: 200 }),
602596
finalUrl: "https://internal.corp.example",

0 commit comments

Comments
 (0)