diff --git a/plugins/feed-discovery/src/feed-discovery.test.ts b/plugins/feed-discovery/src/feed-discovery.test.ts index f2c4383..5a4f9ea 100644 --- a/plugins/feed-discovery/src/feed-discovery.test.ts +++ b/plugins/feed-discovery/src/feed-discovery.test.ts @@ -52,6 +52,7 @@ describe("site probing helpers", () => { await expect(assertSafeHttpUrl("http://127.0.0.1/feed")).rejects.toThrow(/Blocked internal/); await expect(assertSafeHttpUrl("http://[::]/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 4bde9cb..f4c04f8 100644 --- a/plugins/feed-discovery/src/url-safety.ts +++ b/plugins/feed-discovery/src/url-safety.ts @@ -67,6 +67,16 @@ function isBlockedIp(value: string) { if (kind === 6) { const normalized = value.toLowerCase(); + const compatibleDottedIpv4 = /^::(\d+\.\d+\.\d+\.\d+)$/.exec(normalized); + if (compatibleDottedIpv4) { + return isBlockedIp(compatibleDottedIpv4[1]); + } + const compatibleHexIpv4 = /^::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(normalized); + if (compatibleHexIpv4) { + const high = Number.parseInt(compatibleHexIpv4[1], 16); + const low = Number.parseInt(compatibleHexIpv4[2], 16); + return isBlockedIp(`${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`); + } const mappedDottedIpv4 = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(normalized); if (mappedDottedIpv4) { return isBlockedIp(mappedDottedIpv4[1]);