Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions api/utils/ssrf-protection.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}

Expand Down
7 changes: 7 additions & 0 deletions test/unit-tests/api.utils.ssrf-protection.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Loading