Skip to content

fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode#66458

Merged
vincentkoc merged 2 commits intomainfrom
kitsune/pr-64974-carry-main
Apr 14, 2026
Merged

fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode#66458
vincentkoc merged 2 commits intomainfrom
kitsune/pr-64974-carry-main

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • problem: provider HTTP helper requests still forced strict SSRF DNS pinning in proxy-only environments, so remote media-understanding and transcription paths could fail with local ENOTFOUND / EAI_AGAIN before the configured proxy ever saw the request
  • root cause: src/media-understanding/shared.ts called fetchWithSsrFGuard() without selecting trusted_env_proxy mode for env-proxy cases, and there was no shared NO_PROXY matcher to keep the auto-upgrade from bypassing strict mode on direct-bypass targets
  • fix: auto-upgrade only the safe env-proxy cases, preserve strict mode when NO_PROXY bypasses the target or a caller supplies explicit dispatcher policy, and add focused coverage for the proxy-env matcher plus the guarded helper behavior

Fixes #52162.
Related #66245.
Supersedes #64974.

Verification

  • pnpm test:serial src/media-understanding/shared.test.ts src/infra/net/proxy-env.test.ts src/infra/net/fetch-guard.ssrf.test.ts
  • pnpm build

Changelog

  • added unreleased fix entry with Thanks @mjamiv and @vincentkoc

@vincentkoc vincentkoc marked this pull request as ready for review April 14, 2026 09:26
@vincentkoc vincentkoc self-assigned this Apr 14, 2026
@openclaw-barnacle openclaw-barnacle Bot added the maintainer Maintainer-authored PR label Apr 14, 2026
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 14, 2026

🔒 Aisle Security Analysis

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

# Severity Title
1 🟠 High SSRF protections bypassed when auto-upgrading to TRUSTED_ENV_PROXY based on HTTP_PROXY/HTTPS_PROXY env vars
1. 🟠 SSRF protections bypassed when auto-upgrading to TRUSTED_ENV_PROXY based on HTTP_PROXY/HTTPS_PROXY env vars
Property Value
Severity High
CWE CWE-918
Location src/infra/net/fetch-guard.ts:323-327

Description

fetchWithTimeoutGuarded() now auto-selects mode: trusted_env_proxy whenever an HTTP(S) proxy is present in the environment (unless dispatcherPolicy is set or NO_PROXY matches). In trusted_env_proxy mode, fetchWithSsrFGuard() skips resolvePinnedHostnameWithPolicy() entirely and directly instantiates EnvHttpProxyAgent.

Impact:

  • SSRF policy checks are bypassed (blocked hostnames like metadata.google.internal, localhost/internal TLDs, and private/special-use IP literal checks), because those checks live in resolvePinnedHostnameWithPolicy().
  • If the target URL is attacker-controlled (directly, or via a redirect chain), an attacker can potentially fetch internal resources (or cloud metadata) through the configured proxy.
  • If an attacker can influence process environment variables (e.g., multi-tenant/plugin environments, compromised runtime config), setting HTTP_PROXY/HTTPS_PROXY to an attacker-controlled proxy can route outbound provider requests through that proxy (credential/token exfiltration / MITM).

Vulnerable code paths:

  • Auto-upgrade based on env in fetchWithTimeoutGuarded()
  • SSRF checks skipped in fetchWithSsrFGuard() when mode === trusted_env_proxy

Vulnerable code:

// shared.ts
const resolvedMode = options?.mode ?? (
  shouldAutoUpgradeToTrustedEnvProxy({ url, dispatcherPolicy: options?.dispatcherPolicy })
    ? GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY
    : undefined
);
...
...(resolvedMode ? { mode: resolvedMode } : {}),
// fetch-guard.ts
const canUseTrustedEnvProxy =
  mode === GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY && hasProxyEnvConfigured();
if (canUseTrustedEnvProxy) {
  dispatcher = createHttp1EnvHttpProxyAgent();
} else if (params.pinDns === false) {
  await resolvePinnedHostnameWithPolicy(parsedUrl.hostname, ...);
  ...
} else {
  const pinned = await resolvePinnedHostnameWithPolicy(parsedUrl.hostname, ...);
  ...
}

Recommendation

Do not allow trusted_env_proxy to fully bypass SSRF validation for caller-supplied URLs.

Options (pick one, in order of safety):

  1. Require explicit opt-in (no auto-upgrade): only use mode: "trusted_env_proxy" when the caller explicitly passes it.

  2. If auto-upgrade is required for reliability, still enforce pre-proxy SSRF validation in trusted-env mode:

    • Run resolvePinnedHostnameWithPolicy(parsedUrl.hostname, ...) (or at minimum assertAllowedHostOrIpOrThrow-equivalent checks) even when using EnvHttpProxyAgent.
    • If DNS pinning is incompatible with proxies, keep the hostname/IP blocklist and allowlist checks, but skip only the pinning aspect.

Example sketch:

// In fetchWithSsrFGuard()
if (mode === GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY) {// Still block obvious SSRF targets
  await resolvePinnedHostnameWithPolicy(parsedUrl.hostname, {
    lookupFn: params.lookupFn,
    policy: params.policy,
  });// Then dispatch via env proxy without pinning
  dispatcher = createHttp1EnvHttpProxyAgent();
}
  1. Constrain auto-upgrade to known-safe destinations (e.g., provider allowlists), so user-controlled URLs cannot enter trusted_env_proxy mode.

Also document clearly that HTTP_PROXY/HTTPS_PROXY must be treated as operator-controlled configuration, not user input.


Analyzed PR: #66458 at commit 0cb6702

Last updated on: 2026-04-14T09:31:05Z

@vincentkoc vincentkoc merged commit 6ee8e19 into main Apr 14, 2026
8 checks passed
@vincentkoc vincentkoc deleted the kitsune/pr-64974-carry-main branch April 14, 2026 09:29
Copy link
Copy Markdown

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

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: eeb8a1bd89

ℹ️ 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 +184 to +188
(shouldAutoUpgradeToTrustedEnvProxy({
url,
dispatcherPolicy: options?.dispatcherPolicy,
})
? GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-check NO_PROXY on redirect hops before trusted mode

resolvedMode is computed once from the initial URL, but fetchWithSsrFGuard reuses that mode across all redirect hops. In environments with HTTP_PROXY/HTTPS_PROXY plus NO_PROXY, an initial non-bypassed URL can redirect to a NO_PROXY target (for example localhost), and EnvHttpProxyAgent will then connect directly while trusted mode skips pinned-DNS/private-network SSRF checks. This reintroduces the exact bypass the NO_PROXY gate was meant to prevent, so the mode decision needs to be re-evaluated per hop (or forced back to strict on redirected NO_PROXY matches).

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 14, 2026

Greptile Summary

This PR adds matchesNoProxy and hasEnvHttpProxyConfigured helpers to src/infra/net/proxy-env.ts and wires them into fetchWithTimeoutGuarded in src/media-understanding/shared.ts so that provider HTTP requests auto-upgrade to trusted_env_proxy mode when HTTP_PROXY/HTTPS_PROXY is set, fixing ENOTFOUND/EAI_AGAIN failures in proxy-only environments. The three safety gates (explicit dispatcherPolicy, ALL_PROXY-only envs, and NO_PROXY target matches) are well-reasoned, and the new test coverage is thorough.

Confidence Score: 5/5

  • Safe to merge; all remaining findings are P2 style suggestions that do not affect typical deployments.
  • The auto-upgrade logic is conservative and well-gated. The only issue found is an edge-case inconsistency in matchesNoProxy where ?? is used for no_proxy/NO_PROXY precedence instead of the !== undefined guard used by resolveEnvHttpProxyUrl, which only matters when no_proxy="" is explicitly set alongside a non-empty NO_PROXY. This does not affect normal deployments and errs on the safe side (keeps strict mode).
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/infra/net/proxy-env.ts
Line: 82

Comment:
**Inconsistent empty-lower-case precedence vs `resolveEnvHttpProxyUrl`**

`normalizeProxyEnvValue` returns `null` for a set-but-empty string, and `null ?? rhs` still evaluates `rhs`. So `no_proxy=""` with `NO_PROXY="api.openai.com"` will resolve to `"api.openai.com"` here — but the analogous path in `resolveEnvHttpProxyUrl` uses `!== undefined` so an empty `http_proxy=""` correctly suppresses `HTTP_PROXY`. In a proxy-only env, this mismatch could prevent the auto-upgrade from firing for targets listed in `NO_PROXY` even when the operator intended `no_proxy=""` to clear the bypass list.

```suggestion
  const lowerNoProxy = normalizeProxyEnvValue(env.no_proxy);
  const raw = lowerNoProxy !== undefined ? lowerNoProxy : normalizeProxyEnvValue(env.NO_PROXY);
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Update CHANGELOG.md" | Re-trigger Greptile

* SSRF bypass.
*/
export function matchesNoProxy(targetUrl: string, env: NodeJS.ProcessEnv = process.env): boolean {
const raw = normalizeProxyEnvValue(env.no_proxy) ?? normalizeProxyEnvValue(env.NO_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 Inconsistent empty-lower-case precedence vs resolveEnvHttpProxyUrl

normalizeProxyEnvValue returns null for a set-but-empty string, and null ?? rhs still evaluates rhs. So no_proxy="" with NO_PROXY="api.openai.com" will resolve to "api.openai.com" here — but the analogous path in resolveEnvHttpProxyUrl uses !== undefined so an empty http_proxy="" correctly suppresses HTTP_PROXY. In a proxy-only env, this mismatch could prevent the auto-upgrade from firing for targets listed in NO_PROXY even when the operator intended no_proxy="" to clear the bypass list.

Suggested change
const raw = normalizeProxyEnvValue(env.no_proxy) ?? normalizeProxyEnvValue(env.NO_PROXY);
const lowerNoProxy = normalizeProxyEnvValue(env.no_proxy);
const raw = lowerNoProxy !== undefined ? lowerNoProxy : normalizeProxyEnvValue(env.NO_PROXY);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/net/proxy-env.ts
Line: 82

Comment:
**Inconsistent empty-lower-case precedence vs `resolveEnvHttpProxyUrl`**

`normalizeProxyEnvValue` returns `null` for a set-but-empty string, and `null ?? rhs` still evaluates `rhs`. So `no_proxy=""` with `NO_PROXY="api.openai.com"` will resolve to `"api.openai.com"` here — but the analogous path in `resolveEnvHttpProxyUrl` uses `!== undefined` so an empty `http_proxy=""` correctly suppresses `HTTP_PROXY`. In a proxy-only env, this mismatch could prevent the auto-upgrade from firing for targets listed in `NO_PROXY` even when the operator intended `no_proxy=""` to clear the bypass list.

```suggestion
  const lowerNoProxy = normalizeProxyEnvValue(env.no_proxy);
  const raw = lowerNoProxy !== undefined ? lowerNoProxy : normalizeProxyEnvValue(env.NO_PROXY);
```

How can I resolve this? If you propose a fix, please make it concise.

steipete pushed a commit that referenced this pull request Apr 14, 2026
…d env proxy mode (#66458)

* fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode

* Update CHANGELOG.md
kvnkho pushed a commit to kvnkho/openclaw that referenced this pull request Apr 17, 2026
…d env proxy mode (openclaw#66458)

* fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode

* Update CHANGELOG.md
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…d env proxy mode (openclaw#66458)

* fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode

* Update CHANGELOG.md
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…d env proxy mode (openclaw#66458)

* fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode

* Update CHANGELOG.md
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…d env proxy mode (openclaw#66458)

* fix(media-understanding): auto-upgrade provider HTTP helper to trusted env proxy mode

* Update CHANGELOG.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: memory_search remote embeddings fail with ENOTFOUND when env proxy is configured — withRemoteHttpResponse skips TRUSTED_ENV_PROXY mode

1 participant