diff --git a/CHANGELOG.md b/CHANGELOG.md index 37ace8a79ae..54748b67a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Enterprise Fixes: - [data-manager] Fixed editing an event whose key contains `&` creating undeletable duplicate rows in the events table Security Fixes: +- [core] The SSRF address filter now also rejects the RFC 8215 local-use NAT64 prefix (64:ff9b:1::/48), matching how it already handles the well-known NAT64 prefix - [hooks] Internal event hooks are now scoped to the apps the hook belongs to: app creation is a global-admin-only event, and remote-config, cohort, alert and hook-chaining events are only delivered when the event's app is one the hook is scoped to - [compliance-hub] The consents table now returns a fixed set of fields; a projection supplied on the request is no longer used to widen the response beyond the consent columns - [dashboards] Widgets are no longer copied when the copying user has no access to the apps they reference, and widget app ids are validated on widget create and update diff --git a/api/utils/ssrf-protection.js b/api/utils/ssrf-protection.js index 984c4554cd4..9d7d7ab5363 100644 --- a/api/utils/ssrf-protection.js +++ b/api/utils/ssrf-protection.js @@ -83,6 +83,16 @@ function isBlockedIP(ip) { return parsed.toIPv4Address().range() !== 'unicast'; } + // ipaddr.js reports the well-known NAT64 prefix (64:ff9b::/96) as 'rfc6052' + // (blocked by the unicast check below), but the RFC 8215 local-use NAT64 prefix + // (64:ff9b:1::/48) as generic unicast. Block it explicitly so a NAT64 gateway + // cannot translate its embedded IPv4 into an internal address. Network-specific + // NAT64 prefixes carved from an operator's own unicast space cannot be told + // apart by prefix and remain out of scope. + if (parsed.kind() === 'ipv6' && parsed.match(ipaddr.parseCIDR('64:ff9b:1::/48'))) { + return true; + } + return range !== 'unicast'; } diff --git a/test/unit-tests/api.utils.ssrf-protection.js b/test/unit-tests/api.utils.ssrf-protection.js index b0d4691565e..a10ccea533c 100644 --- a/test/unit-tests/api.utils.ssrf-protection.js +++ b/test/unit-tests/api.utils.ssrf-protection.js @@ -24,6 +24,13 @@ describe("SSRF protection utility", function() { it("allows a public IP literal", async function() { (await ssrf.isUrlSafe("http://8.8.8.8/")).safe.should.equal(true); }); + + it("blocks the RFC 8215 local-use NAT64 prefix (64:ff9b:1::/48)", async function() { + (await ssrf.isUrlSafe("http://[64:ff9b:1::7f00:1]/")).safe.should.equal(false); + }); + it("allows a public IPv6 literal", async function() { + (await ssrf.isUrlSafe("http://[2001:4860:4860::8888]/")).safe.should.equal(true); + }); }); describe("safeLookup (connect-time DNS pinning)", function() {