diff --git a/spindle/engines/microvm/read_cache_proxy.go b/spindle/engines/microvm/read_cache_proxy.go --- a/spindle/engines/microvm/read_cache_proxy.go +++ b/spindle/engines/microvm/read_cache_proxy.go @@ -252,7 +252,16 @@ if ip == nil { return fmt.Errorf("refusing to dial non-IP address %q", host) } + bits := 128 + if ip4 := ip.To4(); ip4 != nil { + ip = ip4 + bits = 32 + } for _, ipnet := range blockedNamespaceNets { + _, blockedBits := ipnet.Mask.Size() + if blockedBits != bits { + continue + } if ipnet.Contains(ip) { return fmt.Errorf("refusing to dial %s: %s is blocked for workflow caches", ip, ipnet) } diff --git a/spindle/engines/microvm/read_cache_proxy_test.go b/spindle/engines/microvm/read_cache_proxy_test.go --- a/spindle/engines/microvm/read_cache_proxy_test.go +++ b/spindle/engines/microvm/read_cache_proxy_test.go @@ -122,6 +122,12 @@ } } +func TestCacheProxyGuardAllowsPublicIPv4(t *testing.T) { + if err := refuseSpecialPurposeAddrs("tcp", "104.26.13.82:443", nil); err != nil { + t.Fatalf("public IPv4 address was blocked: %v", err) + } +} + func TestCacheProxyGuardedUpstreamCannotReachBlockedRanges(t *testing.T) { // httptest listens on 127.0.0.1, which is in the blocked ranges; reaching // it would mean a workflow-defined cache can hit the host's loopback