@@ -29,42 +29,29 @@ module SchemaReader =
2929 // Prevent access to private IP ranges (SSRF protection)
3030 let host = url.Host.ToLowerInvariant()
3131
32- // Block localhost and loopback
33- if
34- host = " localhost"
35- || host.StartsWith " 127."
36- || host = " ::1"
37- || host = " 0.0.0.0"
38- then
39- failwithf " Cannot fetch schemas from localhost/loopback addresses: %s (set SsrfProtection=false for development)" host
40-
41- // Block private IP ranges (RFC 1918)
42- if
43- host.StartsWith " 10."
44- || host.StartsWith " 192.168."
45- || host.StartsWith " 172.16."
46- || host.StartsWith " 172.17."
47- || host.StartsWith " 172.18."
48- || host.StartsWith " 172.19."
49- || host.StartsWith " 172.20."
50- || host.StartsWith " 172.21."
51- || host.StartsWith " 172.22."
52- || host.StartsWith " 172.23."
53- || host.StartsWith " 172.24."
54- || host.StartsWith " 172.25."
55- || host.StartsWith " 172.26."
56- || host.StartsWith " 172.27."
57- || host.StartsWith " 172.28."
58- || host.StartsWith " 172.29."
59- || host.StartsWith " 172.30."
60- || host.StartsWith " 172.31."
61- then
62- failwithf " Cannot fetch schemas from private IP addresses: %s (set SsrfProtection=false for development)" host
63-
64- // Block link-local addresses
65- if host.StartsWith " 169.254." then
66- failwithf " Cannot fetch schemas from link-local addresses: %s (set SsrfProtection=false for development)" host
67-
32+ // Block localhost and loopback, and private IP ranges using proper IP address parsing
33+ let isIp , ipAddr = System.Net.IPAddress.TryParse( host)
34+ if isIp then
35+ // Loopback
36+ if System.Net.IPAddress.IsLoopback( ipAddr) || ipAddr.ToString() = " 0.0.0.0" then
37+ failwithf " Cannot fetch schemas from localhost/loopback addresses: %s (set SsrfProtection=false for development)" host
38+ // Private IPv4 ranges
39+ let bytes = ipAddr.GetAddressBytes()
40+ let isPrivate =
41+ // 10.0.0.0/8
42+ ( ipAddr.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork && bytes.[ 0 ] = 10 uy)
43+ // 172.16.0.0/12
44+ || ( ipAddr.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork && bytes.[ 0 ] = 172 uy && bytes.[ 1 ] >= 16 uy && bytes.[ 1 ] <= 31 uy)
45+ // 192.168.0.0/16
46+ || ( ipAddr.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork && bytes.[ 0 ] = 192 uy && bytes.[ 1 ] = 168 uy)
47+ // Link-local 169.254.0.0/16
48+ || ( ipAddr.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork && bytes.[ 0 ] = 169 uy && bytes.[ 1 ] = 254 uy)
49+ if isPrivate then
50+ failwithf " Cannot fetch schemas from private or link-local IP addresses: %s (set SsrfProtection=false for development)" host
51+ else
52+ // Block localhost by name
53+ if host = " localhost" then
54+ failwithf " Cannot fetch schemas from localhost/loopback addresses: %s (set SsrfProtection=false for development)" host
6855 let readSchemaPath ( ignoreSsrfProtection : bool ) ( headersStr : string ) ( schemaPathRaw : string ) =
6956 async {
7057 let uri = Uri schemaPathRaw
0 commit comments