mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix(security): strip custom auth headers on cross-origin redirects
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user