fix(discord,slack): add SSRF policy for media downloads in proxy environments (#25475)

* fix(discord,slack): add SSRF policy for media downloads in proxy environments

Discord and Slack media downloads (attachments, stickers, forwarded
images) call fetchRemoteMedia without any ssrfPolicy. When running
behind a local transparent proxy (Clash, mihomo, Shadowrocket) in
fake-ip mode, DNS returns virtual IPs in the 198.18.0.0/15 range,
which the SSRF guard blocks.

Add per-channel SSRF policy constants—matching the pattern already
applied to Telegram on main—that allowlist known CDN hostnames and
set allowRfc2544BenchmarkRange: true.

Refs #25355, #25322

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(slack): keep raw-fetch allowlist line anchors stable

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Sid
2026-03-02 01:30:10 +08:00
committed by GitHub
parent b9e07ad7b4
commit 39a45121d9
4 changed files with 124 additions and 0 deletions

View File

@@ -2,9 +2,15 @@ import type { ChannelType, Client, Message } from "@buape/carbon";
import { StickerFormatType, type APIAttachment, type APIStickerItem } from "discord-api-types/v10";
import { buildMediaPayload } from "../../channels/plugins/media-payload.js";
import { logVerbose } from "../../globals.js";
import type { SsrFPolicy } from "../../infra/net/ssrf.js";
import { fetchRemoteMedia, type FetchLike } from "../../media/fetch.js";
import { saveMediaBuffer } from "../../media/store.js";
const DISCORD_MEDIA_SSRF_POLICY: SsrFPolicy = {
allowedHostnames: ["cdn.discordapp.com", "media.discordapp.net"],
allowRfc2544BenchmarkRange: true,
};
export type DiscordMediaInfo = {
path: string;
contentType?: string;
@@ -228,6 +234,7 @@ async function appendResolvedMediaFromAttachments(params: {
filePathHint: attachment.filename ?? attachment.url,
maxBytes: params.maxBytes,
fetchImpl: params.fetchImpl,
ssrfPolicy: DISCORD_MEDIA_SSRF_POLICY,
});
const saved = await saveMediaBuffer(
fetched.buffer,
@@ -320,6 +327,7 @@ async function appendResolvedMediaFromStickers(params: {
filePathHint: candidate.fileName,
maxBytes: params.maxBytes,
fetchImpl: params.fetchImpl,
ssrfPolicy: DISCORD_MEDIA_SSRF_POLICY,
});
const saved = await saveMediaBuffer(
fetched.buffer,