fix(api): reject requests with NUL bytes in URL (#869)

## Summary
- Added `NulByteValidationMiddleware` to validate incoming requests
- Returns 400 Bad Request when NUL bytes (%00) detected in URL path or
query
- Prevents PostgreSQL encoding errors from being exposed as 500 errors

## Before
```
GET /v0.1/servers?cursor=%00
→ 500 Internal Server Error
→ "invalid byte sequence for encoding UTF8: 0x00"
```

## After
```
GET /v0.1/servers?cursor=%00
→ 400 Bad Request
→ "Invalid request: query parameters contain null bytes"
```

Fixes #862

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
This commit is contained in:
lif 2026-01-04 01:14:44 +08:00 • committed by GitHub
commit ab6a5a6b6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -17,6 +17,26 @@ import (
"github.com/modelcontextprotocol/registry/internal/telemetry"
)
// NulByteValidationMiddleware rejects requests containing NUL bytes in URL path or query parameters
// This prevents PostgreSQL encoding errors and returns a proper 400 Bad Request
func NulByteValidationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check URL path for NUL bytes
if strings.ContainsRune(r.URL.Path, '\x00') {
http.Error(w, "Invalid request: URL path contains null bytes", http.StatusBadRequest)
return
}
// Check raw query string for NUL bytes
if strings.ContainsRune(r.URL.RawQuery, '\x00') {
http.Error(w, "Invalid request: query parameters contain null bytes", http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
// TrailingSlashMiddleware redirects requests with trailing slashes to their canonical form
func TrailingSlashMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -67,8 +87,8 @@ func NewServer(cfg *config.Config, registryService service.RegistryService, metr
})
// Wrap the mux with middleware stack
// Order: TrailingSlash -> CORS -> Mux
handler := TrailingSlashMiddleware(corsHandler.Handler(mux))
// Order: NulByteValidation -> TrailingSlash -> CORS -> Mux
handler := NulByteValidationMiddleware(TrailingSlashMiddleware(corsHandler.Handler(mux)))
server := &Server{
config: cfg,