mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
NewRestrictedOutboundHTTPClient validates target IPs via a custom DialContext, but when an HTTP proxy is configured (HTTP_PROXY env var) DialContext only validates the proxy's address — the actual target host is never checked. This allows requests to cloud metadata service addresses (169.254.169.254) and other blocked IPs through the proxy. Add a restrictedRoundTripper wrapper that validates the request URL hostname against resolvePermittedOutboundIP before forwarding. This provides defense-in-depth that works regardless of proxy configuration, while the existing DialContext guard continues to prevent DNS rebinding for direct connections.
56 lines
1.5 KiB
Go
56 lines
1.5 KiB
Go
package securityutil
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestRestrictedOutboundHTTPClient_BlocksMetadataServiceEvenViaProxy(t *testing.T) {
|
|
client := NewRestrictedOutboundHTTPClient(0, RestrictedOutboundHTTPOptions{
|
|
AllowedSchemes: []string{"http", "https"},
|
|
AllowPrivateIPs: true,
|
|
AllowLoopback: true,
|
|
})
|
|
|
|
req, err := http.NewRequestWithContext(context.Background(), "GET", "http://169.254.169.254/api/version", nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to create request: %v", err)
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if resp != nil {
|
|
resp.Body.Close()
|
|
}
|
|
if err == nil {
|
|
t.Fatal("expected error for metadata service address, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "metadata service address is not allowed") {
|
|
t.Fatalf("expected 'metadata service address is not allowed', got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRestrictedOutboundHTTPClient_BlocksLinkLocalEvenViaProxy(t *testing.T) {
|
|
client := NewRestrictedOutboundHTTPClient(0, RestrictedOutboundHTTPOptions{
|
|
AllowedSchemes: []string{"http", "https"},
|
|
AllowPrivateIPs: true,
|
|
AllowLoopback: true,
|
|
})
|
|
|
|
req, err := http.NewRequestWithContext(context.Background(), "GET", "http://169.254.10.20/test", nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to create request: %v", err)
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if resp != nil {
|
|
resp.Body.Close()
|
|
}
|
|
if err == nil {
|
|
t.Fatal("expected error for link-local address, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "link-local addresses are not allowed") {
|
|
t.Fatalf("expected 'link-local addresses are not allowed', got %v", err)
|
|
}
|
|
}
|