From 7a4216c52823fe1b64b40608ec84e4745684a2c7 Mon Sep 17 00:00:00 2001 From: Radoslav Dimitrov Date: Mon, 4 May 2026 07:09:57 -0400 Subject: [PATCH] refactor: rename readBody to readErrorBody and cap body size (#1246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow-up to #1241. Two small tweaks to the `readBody` helper: - **Rename `readBody` → `readErrorBody`.** The helper is only ever called on the error path (after a non-2xx status check), where we want a small string for diagnostics. The generic name made it look reusable on the success path, where streaming JSON decoding is the right approach. The new name pins the intended use down. - **Cap the read with `io.LimitReader` (8 KiB).** Defense in depth — error diagnostics never need more than a few KB, and we shouldn't buffer an arbitrarily large body from an upstream just to format an error message. 8 KiB is well above any realistic GitHub API or JWKS error response. No behavior change on the happy path. On the unhappy path, error messages are now bounded. ## Test plan - [x] `go build ./...` - [x] `go test ./internal/api/handlers/v0/auth/...` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- internal/api/handlers/v0/auth/common.go | 8 ++++++-- internal/api/handlers/v0/auth/github_at.go | 4 ++-- internal/api/handlers/v0/auth/github_oidc.go | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/api/handlers/v0/auth/common.go b/internal/api/handlers/v0/auth/common.go index 2c81303..5d91047 100644 --- a/internal/api/handlers/v0/auth/common.go +++ b/internal/api/handlers/v0/auth/common.go @@ -21,8 +21,12 @@ import ( "github.com/modelcontextprotocol/registry/internal/config" ) -func readBody(r io.Reader) string { - b, _ := io.ReadAll(r) +// readErrorBody reads an upstream error response body for inclusion in an +// error message. The cap protects against a misbehaving upstream returning a +// huge body — error diagnostics never need more than a few KB. +func readErrorBody(r io.Reader) string { + const maxErrorBodySize = 8 * 1024 + b, _ := io.ReadAll(io.LimitReader(r, maxErrorBodySize)) return string(b) } diff --git a/internal/api/handlers/v0/auth/github_at.go b/internal/api/handlers/v0/auth/github_at.go index b495f4d..af5e793 100644 --- a/internal/api/handlers/v0/auth/github_at.go +++ b/internal/api/handlers/v0/auth/github_at.go @@ -122,7 +122,7 @@ func (h *GitHubHandler) getGitHubUser(ctx context.Context, token string) (*GitHu defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, readBody(resp.Body)) + return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, readErrorBody(resp.Body)) } var user GitHubUserOrOrg @@ -150,7 +150,7 @@ func (h *GitHubHandler) getGitHubUserOrgs(ctx context.Context, username string, defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, readBody(resp.Body)) + return nil, fmt.Errorf("GitHub API error (status %d): %s", resp.StatusCode, readErrorBody(resp.Body)) } var orgs []GitHubUserOrOrg diff --git a/internal/api/handlers/v0/auth/github_oidc.go b/internal/api/handlers/v0/auth/github_oidc.go index 6a6761b..5ce38ac 100644 --- a/internal/api/handlers/v0/auth/github_oidc.go +++ b/internal/api/handlers/v0/auth/github_oidc.go @@ -148,7 +148,7 @@ func (v *GitHubOIDCValidator) fetchJWKS(ctx context.Context) (*JWKS, error) { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("JWKS endpoint returned status %d: %s", resp.StatusCode, readBody(resp.Body)) + return nil, fmt.Errorf("JWKS endpoint returned status %d: %s", resp.StatusCode, readErrorBody(resp.Body)) } var jwks JWKS