VYPR
High severityNVD Advisory· Published Mar 23, 2026· Updated Mar 24, 2026

OpenClaw < 2026.3.7 - Custom Authorization Header Leakage via Cross-Origin Redirects

CVE-2026-32913

Description

OpenClaw before 2026.3.7 contains an improper header validation vulnerability in fetchWithSsrFGuard that forwards custom authorization headers across cross-origin redirects. Attackers can trigger redirects to different origins to intercept sensitive headers like X-Api-Key and Private-Token intended for the original destination.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.72026.3.7

Affected products

1

Patches

1
46715371b061

fix(security): strip custom auth headers on cross-origin redirects

https://github.com/openclaw/openclawPeter SteinbergerMar 7, 2026via ghsa
3 files changed · +33 10
  • CHANGELOG.md+1 0 modified
    @@ -601,6 +601,7 @@ Docs: https://docs.openclaw.ai
     ### Fixes
     
     - Models/provider config precedence: prefer exact `models.providers.<name>` matches before normalized provider aliases in embedded model resolution, preventing alias/canonical key collisions from applying the wrong provider `api`, `baseUrl`, or headers. (#35934) thanks @RealKai42.
    +- Network/fetch guard redirect auth stripping: switch cross-origin redirect handling in `fetchWithSsrFGuard` from a narrow sensitive-header denylist to a safe-header allowlist so custom auth headers like `X-Api-Key` and `Private-Token` no longer leak on origin changes. Thanks @Rickidevs for reporting.
     - Logging/Subsystem console timestamps: route subsystem console timestamp rendering through `formatConsoleTimestamp(...)` so `pretty` and timestamp-prefix output use local timezone formatting consistently instead of inline UTC `toISOString()` paths. (#25970) Thanks @openperf.
     - Feishu/Multi-account + reply reliability: add `channels.feishu.defaultAccount` outbound routing support with schema validation, prevent inbound preview text from leaking into prompt system events, keep quoted-message extraction text-first (post/interactive/file placeholders instead of raw JSON), route Feishu video sends as `msg_type: "file"`, and avoid websocket event blocking by using non-blocking event handling in monitor dispatch. Landed from contributor PRs #31209, #29610, #30432, #30331, and #29501. Thanks @stakeswky, @hclsys, @bmendonca3, @patrick-yingxi-pan, and @zwffff.
     - Feishu/Target routing + replies + dedupe: normalize provider-prefixed targets (`feishu:`/`lark:`), prefer configured `channels.feishu.defaultAccount` for tool execution, honor Feishu outbound `renderMode` in adapter text/caption sends, fall back to normal send when reply targets are withdrawn/deleted, and add synchronous in-memory dedupe guard for concurrent duplicate inbound events. Landed from contributor PRs #30428, #30438, #29958, #30444, and #29463. Thanks @bmendonca3 and @Yaxuan42.
    
  • src/infra/net/fetch-guard.ssrf.test.ts+11 1 modified
    @@ -154,7 +154,12 @@ describe("fetchWithSsrFGuard hardening", () => {
               "Proxy-Authorization": "Basic c2VjcmV0",
               Cookie: "session=abc",
               Cookie2: "legacy=1",
    +          "X-Api-Key": "custom-secret",
    +          "Private-Token": "private-secret",
               "X-Trace": "1",
    +          Accept: "application/json",
    +          "Content-Type": "application/json",
    +          "User-Agent": "OpenClaw-Test/1.0",
             },
           },
         });
    @@ -164,7 +169,12 @@ describe("fetchWithSsrFGuard hardening", () => {
         expect(headers.get("proxy-authorization")).toBeNull();
         expect(headers.get("cookie")).toBeNull();
         expect(headers.get("cookie2")).toBeNull();
    -    expect(headers.get("x-trace")).toBe("1");
    +    expect(headers.get("x-api-key")).toBeNull();
    +    expect(headers.get("private-token")).toBeNull();
    +    expect(headers.get("x-trace")).toBeNull();
    +    expect(headers.get("accept")).toBe("application/json");
    +    expect(headers.get("content-type")).toBe("application/json");
    +    expect(headers.get("user-agent")).toBe("OpenClaw-Test/1.0");
         await result.release();
       });
     
    
  • src/infra/net/fetch-guard.ts+21 9 modified
    @@ -52,12 +52,21 @@ type GuardedFetchPresetOptions = Omit<
     >;
     
     const DEFAULT_MAX_REDIRECTS = 3;
    -const CROSS_ORIGIN_REDIRECT_SENSITIVE_HEADERS = [
    -  "authorization",
    -  "proxy-authorization",
    -  "cookie",
    -  "cookie2",
    -];
    +const CROSS_ORIGIN_REDIRECT_SAFE_HEADERS = new Set([
    +  "accept",
    +  "accept-encoding",
    +  "accept-language",
    +  "cache-control",
    +  "content-language",
    +  "content-type",
    +  "if-match",
    +  "if-modified-since",
    +  "if-none-match",
    +  "if-unmodified-since",
    +  "pragma",
    +  "range",
    +  "user-agent",
    +]);
     
     export function withStrictGuardedFetchMode(params: GuardedFetchPresetOptions): GuardedFetchOptions {
       return { ...params, mode: GUARDED_FETCH_MODE.STRICT };
    @@ -87,9 +96,12 @@ function stripSensitiveHeadersForCrossOriginRedirect(init?: RequestInit): Reques
       if (!init?.headers) {
         return init;
       }
    -  const headers = new Headers(init.headers);
    -  for (const header of CROSS_ORIGIN_REDIRECT_SENSITIVE_HEADERS) {
    -    headers.delete(header);
    +  const incoming = new Headers(init.headers);
    +  const headers = new Headers();
    +  for (const [key, value] of incoming.entries()) {
    +    if (CROSS_ORIGIN_REDIRECT_SAFE_HEADERS.has(key.toLowerCase())) {
    +      headers.set(key, value);
    +    }
       }
       return { ...init, headers };
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.