fix(security): block 198.18.0.0/15 and 240.0.0.0/4 in SSRF protection (#1269)

Add RFC 2544 benchmarking range (198.18.0.0/15) and reserved range
(240.0.0.0/4) to both SSRF blocklists (security package + web_fetch
tool) to prevent internal network access via these special-use IPs.

Closes #1218
This commit is contained in:
Thanh_Dang authored and GitHub committed 2026-06-24 14:12:38 +07:00
1 parent 505b7a9d99
commit 12a0168271
4 files changed
+68 -1

No files matched your search

+4
View File
@@ -52,6 +52,10 @@ func init() {
"172.16.0.0/12",
"192.168.0.0/16",
"fc00::/7",
// Benchmarking (RFC 2544)
"198.18.0.0/15",
// Reserved for future use
"240.0.0.0/4",
// Multicast
"224.0.0.0/4",
"ff00::/8",
+14
View File
@@ -45,6 +45,20 @@ func TestValidate_RejectsRFC1918(t *testing.T) {
}
}
func TestValidate_RejectsBenchmarking(t *testing.T) {
_, _, err := Validate("http://198.18.1.1/")
if err == nil {
t.Fatal("expected error for benchmarking range (198.18.0.0/15), got nil")
}
}
func TestValidate_RejectsReserved(t *testing.T) {
_, _, err := Validate("http://240.1.2.3/")
if err == nil {
t.Fatal("expected error for reserved range (240.0.0.0/4), got nil")
}
}
func TestValidate_RejectsMulticast(t *testing.T) {
_, _, err := Validate("http://224.0.0.1/")
if err == nil {
+3 -1
View File
@@ -131,7 +131,9 @@ func isPrivateIP(ipStr string) bool {
{"169.254.0.0", 16}, // link-local
{"172.16.0.0", 12}, // private
{"192.168.0.0", 16}, // private
{"100.64.0.0", 10}, // carrier-grade NAT
{"100.64.0.0", 10}, // carrier-grade NAT (RFC 6598)
{"198.18.0.0", 15}, // benchmarking (RFC 2544)
{"240.0.0.0", 4}, // reserved for future use
}
for _, r := range privateRanges {
+47
View File
@@ -0,0 +1,47 @@
package tools
import "testing"
func TestIsPrivateIP(t *testing.T) {
blocked := []struct {
ip string
desc string
}{
{"10.0.0.1", "RFC 1918 class A"},
{"172.16.5.1", "RFC 1918 class B"},
{"192.168.1.1", "RFC 1918 class C"},
{"127.0.0.1", "loopback"},
{"169.254.169.254", "link-local / cloud metadata"},
{"100.64.0.1", "carrier-grade NAT"},
{"198.18.1.1", "benchmarking (RFC 2544)"},
{"198.19.255.1", "benchmarking upper (RFC 2544)"},
{"240.1.2.3", "reserved for future use"},
{"255.255.255.255", "reserved broadcast"},
{"::1", "IPv6 loopback"},
{"fe80::1", "IPv6 link-local"},
{"fc00::1", "IPv6 unique local"},
}
for _, tc := range blocked {
t.Run(tc.desc, func(t *testing.T) {
if !isPrivateIP(tc.ip) {
t.Errorf("expected %s (%s) to be blocked", tc.ip, tc.desc)
}
})
}
allowed := []struct {
ip string
desc string
}{
{"8.8.8.8", "Google DNS"},
{"93.184.216.34", "example.com"},
{"198.51.100.1", "public IP near benchmarking range"},
}
for _, tc := range allowed {
t.Run(tc.desc, func(t *testing.T) {
if isPrivateIP(tc.ip) {
t.Errorf("expected %s (%s) to be allowed", tc.ip, tc.desc)
}
})
}
}