From b1b23a50c762f7a46125ce2e1c9bffc4da7aa0f1 Mon Sep 17 00:00:00 2001 From: jsdavid278-cyber Date: Sun, 28 Jun 2026 01:54:18 -0600 Subject: [PATCH] fix(feed-discovery): block reserved feed IP targets --- plugins/feed-discovery/src/feed-discovery.test.ts | 9 +++++++++ plugins/feed-discovery/src/url-safety.ts | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/plugins/feed-discovery/src/feed-discovery.test.ts b/plugins/feed-discovery/src/feed-discovery.test.ts index 4c28b96..04b5434 100644 --- a/plugins/feed-discovery/src/feed-discovery.test.ts +++ b/plugins/feed-discovery/src/feed-discovery.test.ts @@ -60,8 +60,17 @@ describe("site probing helpers", () => { }); it("blocks private SSRF targets", async () => { + await expect(assertSafeHttpUrl("http://0.0.0.0/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("http://127.0.0.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://192.0.2.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://198.18.0.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://198.51.100.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://203.0.113.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://224.0.0.1/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://240.0.0.1/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("http://[::]/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://[2001:db8::1]/feed")).rejects.toThrow(/Blocked internal/); + await expect(assertSafeHttpUrl("http://[ff02::1]/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("http://[::ffff:192.168.1.10]/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("http://[::192.168.1.10]/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("file:///etc/passwd")).rejects.toThrow(/Unsupported URL protocol/); diff --git a/plugins/feed-discovery/src/url-safety.ts b/plugins/feed-discovery/src/url-safety.ts index f4c04f8..d44d87e 100644 --- a/plugins/feed-discovery/src/url-safety.ts +++ b/plugins/feed-discovery/src/url-safety.ts @@ -53,14 +53,20 @@ function isBlockedIp(value: string) { const kind = isIP(value); if (kind === 4) { const parts = value.split(".").map((part) => Number(part)); - const [a, b] = parts; + const [a, b, c] = parts; return ( a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || + (a === 192 && b === 0 && c === 0) || + (a === 192 && b === 0 && c === 2) || (a === 192 && b === 168) || + (a === 198 && (b === 18 || b === 19)) || + (a === 198 && b === 51 && c === 100) || + (a === 203 && b === 0 && c === 113) || + a >= 224 || (a === 100 && b >= 64 && b <= 127) ); } @@ -90,9 +96,13 @@ function isBlockedIp(value: string) { return ( normalized === "::" || normalized === "::1" || + normalized.startsWith("100:") || + normalized.startsWith("2001:2:") || + normalized.startsWith("2001:db8:") || normalized.startsWith("fc") || normalized.startsWith("fd") || - normalized.startsWith("fe80") + /^fe[89ab][0-9a-f]:/.test(normalized) || + normalized.startsWith("ff") ); }