mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-29 19:01:44 +00:00
Telegram: tighten media SSRF policy (#56004)
* Telegram: tighten media SSRF policy * Telegram: restrict media downloads to configured hosts * Telegram: preserve custom media apiRoot hosts
This commit is contained in:
@@ -155,8 +155,8 @@ async function expectTransientGetFileRetrySuccess() {
|
||||
expect.objectContaining({
|
||||
url: `https://api.telegram.org/file/bot${BOT_TOKEN}/voice/file_0.oga`,
|
||||
ssrfPolicy: {
|
||||
allowRfc2544BenchmarkRange: true,
|
||||
allowedHostnames: ["api.telegram.org"],
|
||||
allowRfc2544BenchmarkRange: false,
|
||||
hostnameAllowlist: ["api.telegram.org"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -514,4 +514,29 @@ describe("resolveMedia original filename preservation", () => {
|
||||
);
|
||||
expect(result).not.toBeNull();
|
||||
});
|
||||
|
||||
it("allows a configured custom apiRoot host while keeping the hostname allowlist", async () => {
|
||||
const getFile = vi.fn().mockResolvedValue({ file_path: "documents/file_42.pdf" });
|
||||
mockPdfFetchAndSave("file_42.pdf");
|
||||
|
||||
const ctx = makeCtx("document", getFile);
|
||||
const result = await resolveMedia(
|
||||
ctx,
|
||||
MAX_MEDIA_BYTES,
|
||||
BOT_TOKEN,
|
||||
undefined,
|
||||
"http://192.168.1.50:8081/custom-bot-api/",
|
||||
);
|
||||
|
||||
expect(fetchRemoteMedia).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
ssrfPolicy: {
|
||||
hostnameAllowlist: ["api.telegram.org", "192.168.1.50"],
|
||||
allowedHostnames: ["192.168.1.50"],
|
||||
allowRfc2544BenchmarkRange: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,21 +20,28 @@ const GrammyErrorCtor: typeof GrammyError | undefined =
|
||||
|
||||
function buildTelegramMediaSsrfPolicy(apiRoot?: string) {
|
||||
const hostnames = ["api.telegram.org"];
|
||||
let allowedHostnames: string[] | undefined;
|
||||
if (apiRoot) {
|
||||
try {
|
||||
const customHost = new URL(apiRoot).hostname;
|
||||
if (customHost && !hostnames.includes(customHost)) {
|
||||
hostnames.push(customHost);
|
||||
// A configured custom Bot API host is an explicit operator override and
|
||||
// may legitimately live on a private network (for example, self-hosted
|
||||
// Bot API or an internal reverse proxy). Keep that host reachable while
|
||||
// still enforcing resolved-IP checks for the default public host.
|
||||
allowedHostnames = [customHost];
|
||||
}
|
||||
} catch {
|
||||
// invalid URL; fall through to default
|
||||
}
|
||||
}
|
||||
return {
|
||||
// Telegram file downloads should trust the API hostname even when DNS/proxy
|
||||
// resolution maps to private/internal ranges in restricted networks.
|
||||
allowedHostnames: hostnames,
|
||||
allowRfc2544BenchmarkRange: true,
|
||||
// Restrict media downloads to the configured Telegram API hosts while still
|
||||
// enforcing SSRF checks on the resolved and redirected targets.
|
||||
hostnameAllowlist: hostnames,
|
||||
...(allowedHostnames ? { allowedHostnames } : {}),
|
||||
allowRfc2544BenchmarkRange: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user