From 389d35468c7609ed8b44355dd51e9858def896ea Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Sun, 1 Mar 2026 11:19:14 -0600 Subject: [PATCH] fix(slack): merge auth-header forwarding and html media guard --- CHANGELOG.md | 1 + src/slack/monitor/media.test.ts | 9 +++++---- src/slack/monitor/media.ts | 15 +++++---------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c170c23f35..b92145d6932 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ Docs: https://docs.openclaw.ai ### Fixes - Slack/Bot attachment-only messages: when `allowBots: true`, bot messages with empty `text` now include non-forwarded attachment `text`/`fallback` content so webhook alerts are not silently dropped. (#27616) +- Slack/Inbound media auth + HTML guard: keep Slack auth headers on forwarded shared attachment image downloads, and reject login/error HTML payloads (while allowing expected `.html` uploads) when resolving Slack media so auth failures do not silently pass as files. (#18642) - Slack/Security ingress mismatch guard: drop slash-command and interaction payloads when app/team identifiers do not match the active Slack account context (including nested `team.id` interaction payloads), preventing cross-app or cross-workspace payload injection into system-event handling. (#29091) Thanks @Solvely-Colin. - Cron/Failure alerts: add configurable repeated-failure alerting with per-job overrides and Web UI cron editor support (`inherit|disabled|custom` with threshold/cooldown/channel/target fields). (#24789) Thanks xbrak. - Cron/Isolated model defaults: resolve isolated cron `subagents.model` (including object-form `primary`) through allowlist-aware model selection so isolated cron runs honor subagent model defaults unless explicitly overridden by job payload model. (#11474) Thanks @AnonO6. diff --git a/src/slack/monitor/media.test.ts b/src/slack/monitor/media.test.ts index c84324b9e5d..b6ad169feb2 100644 --- a/src/slack/monitor/media.test.ts +++ b/src/slack/monitor/media.test.ts @@ -571,10 +571,11 @@ describe("resolveSlackAttachmentContent", () => { }, ], }); - expect(mockFetch).toHaveBeenCalledWith("https://files.slack.com/forwarded.jpg", { - headers: { Authorization: "Bearer xoxb-test-token" }, - redirect: "manual", - }); + const firstCall = mockFetch.mock.calls[0]; + expect(firstCall?.[0]).toBe("https://files.slack.com/forwarded.jpg"); + const firstInit = firstCall?.[1]; + expect(firstInit?.redirect).toBe("manual"); + expect(new Headers(firstInit?.headers).get("Authorization")).toBe("Bearer xoxb-test-token"); }); }); diff --git a/src/slack/monitor/media.ts b/src/slack/monitor/media.ts index f8b06585624..a71523b43ad 100644 --- a/src/slack/monitor/media.ts +++ b/src/slack/monitor/media.ts @@ -1,7 +1,6 @@ import type { WebClient as SlackWebClient } from "@slack/web-api"; import { normalizeHostname } from "../../infra/net/hostname.js"; import type { FetchLike } from "../../media/fetch.js"; -import { logWarn } from "../../logger.js"; import { fetchRemoteMedia } from "../../media/fetch.js"; import { saveMediaBuffer } from "../../media/store.js"; import type { SlackAttachment, SlackFile } from "../types.js"; @@ -70,11 +69,6 @@ function createSlackMediaFetch(token: string): FetchLike { }; } -function looksLikeHtmlBuffer(buffer: Buffer): boolean { - const head = buffer.subarray(0, 512).toString("utf-8").replace(/^\s+/, "").toLowerCase(); - return head.startsWith("