Harden HTTP defaults and proxy header trust.

Add explicit server timeout/header limits, require trusted proxy CIDRs when honoring forwarded IP headers, and document single-instance storage expectations.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 21:09:00 -05:00
parent dbf112a5b7
commit dbb72da312
7 changed files with 246 additions and 27 deletions
+23 -10
View File
@@ -17,7 +17,7 @@ func TestAllowlistMiddlewareDeniesAndAllowsByIP(t *testing.T) {
logger := log.New(io.Discard, "", 0)
allowed := []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}
mw := AllowlistMiddleware(allowed, false, logger)
mw := AllowlistMiddleware(allowed, false, nil, logger)
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
@@ -46,7 +46,8 @@ func TestAllowlistMiddlewareHonorsProxyHeaderWhenTrusted(t *testing.T) {
logger := log.New(io.Discard, "", 0)
allowed := []netip.Prefix{netip.MustParsePrefix("203.0.113.5/32")}
mw := AllowlistMiddleware(allowed, true, logger)
trustedProxies := []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}
mw := AllowlistMiddleware(allowed, true, trustedProxies, logger)
handler := mw(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
@@ -66,7 +67,7 @@ func TestRateLimitMiddlewareKeysByClientIP(t *testing.T) {
t.Parallel()
limiter := NewRateLimiter(60, 1)
handler := RateLimitMiddleware(limiter, false)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
handler := RateLimitMiddleware(limiter, false, nil)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
@@ -98,7 +99,7 @@ func TestRateLimitMiddlewareKeysByClientIP(t *testing.T) {
func TestAllowlistMiddlewareNoRestrictionsReturnsNext(t *testing.T) {
t.Parallel()
handler := AllowlistMiddleware(nil, false, log.New(io.Discard, "", 0))(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
handler := AllowlistMiddleware(nil, false, nil, log.New(io.Discard, "", 0))(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusAccepted)
}))
req := httptest.NewRequest(http.MethodPost, "/api/scratch", nil)
@@ -115,7 +116,7 @@ func TestAllowlistMiddlewareRejectsUnknownClientIP(t *testing.T) {
logger := log.New(io.Discard, "", 0)
allowed := []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}
handler := AllowlistMiddleware(allowed, false, logger)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
handler := AllowlistMiddleware(allowed, false, nil, logger)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
req := httptest.NewRequest(http.MethodPost, "/api/scratch", nil)
@@ -131,7 +132,7 @@ func TestRateLimitMiddlewareUnknownIP(t *testing.T) {
t.Parallel()
limiter := NewRateLimiter(60, 1)
handler := RateLimitMiddleware(limiter, false)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
handler := RateLimitMiddleware(limiter, false, nil)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
req := httptest.NewRequest(http.MethodPost, "/api/scratch", nil)
@@ -147,7 +148,7 @@ func TestRateLimitMiddleware429PayloadAndRetryHeader(t *testing.T) {
t.Parallel()
limiter := NewRateLimiter(1, 1)
handler := RateLimitMiddleware(limiter, false)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
handler := RateLimitMiddleware(limiter, false, nil)(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}))
req1 := httptest.NewRequest(http.MethodPost, "/api/scratch", nil)
@@ -195,7 +196,7 @@ func TestExtractClientIPFallbacks(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "203.0.113.9"
ip, ok := extractClientIP(req, false)
ip, ok := extractClientIP(req, false, nil)
if !ok || ip.String() != "203.0.113.9" {
t.Fatalf("extract direct ip = (%v,%v), want (203.0.113.9,true)", ip, ok)
}
@@ -204,14 +205,26 @@ func TestExtractClientIPFallbacks(t *testing.T) {
req2.RemoteAddr = "192.0.2.50:8080"
req2.Header.Set("X-Forwarded-For", "bad,198.51.100.1")
req2.Header.Set("X-Real-IP", "198.51.100.5")
ip2, ok2 := extractClientIP(req2, true)
ip2, ok2 := extractClientIP(req2, true, []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24")})
if !ok2 || ip2.String() != "198.51.100.5" {
t.Fatalf("extract x-real-ip = (%v,%v), want (198.51.100.5,true)", ip2, ok2)
}
req3 := httptest.NewRequest(http.MethodGet, "/", nil)
req3.RemoteAddr = "still-not-an-ip"
if _, ok3 := extractClientIP(req3, false); ok3 {
if _, ok3 := extractClientIP(req3, false, nil); ok3 {
t.Fatalf("extractClientIP() ok = true, want false")
}
}
func TestExtractClientIPIgnoresHeadersFromUntrustedProxy(t *testing.T) {
t.Parallel()
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.RemoteAddr = "203.0.113.10:8080"
req.Header.Set("X-Forwarded-For", "198.51.100.5")
ip, ok := extractClientIP(req, true, []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")})
if !ok || ip.String() != "203.0.113.10" {
t.Fatalf("extractClientIP() = (%v,%v), want (203.0.113.10,true)", ip, ok)
}
}