Skip to content

fix(broker): sanitize OAuth callback error & token-endpoint failures (MCP-1045)#739

Merged
Dumbris merged 1 commit into
mainfrom
fix/mcp1045-oauth-error-leak
Jun 21, 2026
Merged

fix(broker): sanitize OAuth callback error & token-endpoint failures (MCP-1045)#739
Dumbris merged 1 commit into
mainfrom
fix/mcp1045-oauth-error-leak

Conversation

@Dumbris

@Dumbris Dumbris commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Addresses the MCP-1045 / T12 security review verdict (Codex request_changes) on the credential-broker (spec 074). Two paths leaked authorization-server-controlled strings into logs/responses, violating the FR-029 / SC-005 no secret in logs/responses/audit invariant. PR #694 was already merged, so this is the follow-up fix; the Paperclip comment remains the review-of-record.

Finding 1 — connect-callback raw error leak

internal/serveredition/api/credential_handlers.go coerced the raw ?error= query value only for the audit sink, but still:

  • logged it verbatim (reason), and
  • reflected it into the browser redirect's credential_error param.

Both now use the sanitized label (sanitizeCallbackError). An upstream AS fully controls this value and could embed secrets or echoed input.

Finding 2 — token-endpoint raw body leak

internal/serveredition/broker/oauth_connector.go::postToken returned the raw token-endpoint response body in its error, which is logged on the connect path (credential_handlers.go) and the refresh path (credential_resolver.go). A hostile/misconfigured AS can embed access/refresh tokens, client details, or echoed request data there.

postToken now returns only the HTTP status plus an allowlisted RFC 6749 §5.2 OAuth error code (via new sanitizedTokenEndpointError), mirroring the RFC 8693 exchanger's existing sanitizedError. Non-allowlisted codes and the raw body/error_description are dropped.

Tests (TDD — written failing first)

  • TestCredentialsCallback_Denied_RedirectSanitized — redirect credential_error carries the coerced label, never the raw AS string.
  • TestOAuthConnector_Complete_TokenEndpointError_NoBodyLeak — a token-stuffed error body never reaches the returned error.
  • TestOAuthConnector_TokenEndpointError_AllowlistedCode — allowlisted codes pass through; others are dropped.

Verification

  • go test -tags server ./internal/serveredition/broker ./internal/serveredition/api ./internal/transport
  • go test -tags server -race ./internal/serveredition/broker ./internal/serveredition/api
  • go build -tags server ./cmd/mcpproxy and go build ./cmd/mcpproxy
  • New server-edition code lints clean (golangci-lint --build-tags server).

Docs

  • docs/features/idp-token-storage.md updated to state the connect error flag is a coerced, secret-free label.

Related #694

…s (MCP-1045)

The T12 security review (Codex, request_changes) found two paths that leak
authorization-server-controlled strings into logs and responses, violating the
FR-029/SC-005 'no secret in logs/responses/audit' invariant:

1. The credential connect callback coerced the raw ?error= value only for the
   audit sink, but still logged it verbatim and reflected it into the browser
   redirect's credential_error param. Now the sanitized label is used on all
   three sinks (audit, log, redirect).

2. OAuthConnector.postToken returned the raw token-endpoint response body in its
   error, which is logged on the connect and refresh paths. A hostile/misconfigured
   AS could embed access/refresh tokens or echoed input there. postToken now
   surfaces only the HTTP status plus an allowlisted RFC 6749 §5.2 error code,
   mirroring the RFC 8693 exchanger's sanitizedError.

Adds regression tests covering the redirect/log leak and the token-body leak.

Related #694, Related MCP-1045
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4cd64be
Status: ✅  Deploy successful!
Preview URL: https://2f3271f9.mcpproxy-docs.pages.dev
Branch Preview URL: https://fix-mcp1045-oauth-error-leak.mcpproxy-docs.pages.dev

View logs

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

📦 Build Artifacts

Workflow Run: View Run
Branch: fix/mcp1045-oauth-error-leak

Available Artifacts

  • archive-darwin-amd64 (28 MB)
  • archive-darwin-arm64 (25 MB)
  • archive-linux-amd64 (16 MB)
  • archive-linux-arm64 (14 MB)
  • archive-windows-amd64 (28 MB)
  • archive-windows-arm64 (25 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (21 MB)
  • installer-dmg-darwin-arm64 (19 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 27859650989 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@Dumbris Dumbris enabled auto-merge (squash) June 21, 2026 05:31

@mcpproxy-gatekeeper mcpproxy-gatekeeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gatekeeper approval — review verdict: ACCEPT (by KimiReviewer, model-diverse fallback).

This approval is posted automatically by the MCPProxy Gatekeeper App on behalf of KimiReviewer — the model-diverse reviewer-fallback reviewer of record (verdict lives in the Paperclip review thread). Author≠approver satisfied; QA + CI gates enforced separately.

Auto-approved per Model B (MCP-1249) + reviewer-fallback (MCP-3066).

@Dumbris Dumbris merged commit dde5fd6 into main Jun 21, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants