Skip to content

[BUG][SECURITY]: Fallback auth token precedence differs from middleware in stateful sessionsΒ #3019

@crivetimihai

Description

@crivetimihai

🐞 Bug Summary

The stateful session fallback auth path in _get_request_context_or_default() resolves user identity through require_auth_override() β†’ require_auth(), which prioritizes cookie tokens over Authorization headers. The primary middleware auth path (streamable_http_auth) uses Authorization header only. If a request carries both a valid Authorization header and a different valid cookie JWT, the middleware authenticates as the header user but the fallback authenticates as the cookie user, causing identity drift.


🧩 Affected Component

  • Federation or Transports
  • mcpgateway - API

πŸ” Steps to Reproduce

  1. Enable stateful sessions (USE_STATEFUL_SESSIONS=true)
  2. Send a request to /servers/{id}/mcp/ with:
    • Authorization: Bearer <token-for-user-A>
    • Cookie jwt_token=<token-for-user-B>
  3. On the initial request, streamable_http_auth authenticates as user A (header only)
  4. On a subsequent request where ContextVars are stale, _get_request_context_or_default() falls back and authenticates as user B (cookie takes precedence in require_auth)

πŸ€” Expected Behavior

The fallback auth path should use the same token precedence as the middleware β€” Authorization header first, cookie as fallback only when no header is present.


πŸ“ Code References

  • Middleware (header-only): mcpgateway/transports/streamablehttp_transport.py:2200-2205
  • Fallback calls require_auth_override: mcpgateway/transports/streamablehttp_transport.py:1002
  • require_auth token precedence (cookie first): mcpgateway/utils/verify_credentials.py:389-401

πŸ’‘ Suggested Fix

In _get_request_context_or_default(), align token precedence with middleware by only passing the cookie when no Authorization header is present:

auth_header = req_headers.get("authorization")
cookie_token = request.cookies.get("jwt_token") if not auth_header else None

Or create a dedicated require_auth_header_first() variant that matches the middleware's precedence.


πŸ“ Practical Risk Assessment

Low practical risk β€” this only triggers when:

  1. Stateful session ContextVars are stale (fallback fires)
  2. Request carries BOTH a valid Authorization header AND a different valid cookie JWT
  3. MCP SDK clients use headers (not cookies); browser Admin UI uses cookies (not MCP transport)

The scenario of both being present with different identities is unusual in practice.


Key Value
Version or commit main (pre-existing, noted during PR #2974 review)
Runtime Python 3.13
Severity Medium (requires unusual conditions, but could cause authorization inconsistency)

Metadata

Metadata

Assignees

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafebugSomething isn't workingpythonPython / backend development (FastAPI)securityImproves security

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions