Skip to content

Run unauthenticated-exposure probes over a fresh anonymous session - #3

Merged
hackwither merged 1 commit into
mainfrom
fix/anon-transport-state
Sep 4, 2026
Merged

hackwither merged 1 commit into
mainfrom
fix/anon-transport-state

Conversation

@hackwither

Copy link
Copy Markdown
Owner

REAP's "unauthenticated exposure" probes re-used the session created with
--auth-header and merely suppressed the per-request Authorization header via
WithNoAuth(). That does not undo transport state established out-of-band:
WebSocket auth is bound to the upgrade handshake, streamable HTTP retains a
captured Mcp-Session-Id, and legacy SSE keeps an authenticated long-lived
stream. On WebSocket especially, WithNoAuth() is ignored entirely, so an
authenticated tool list could be reported as anonymous exposure (issue #1).

  • Add AnonymousSession() to Session, SSESession and WSSession: a fresh,
    credential-free connection reusing the shared httpx.Client. Add Close() to
    SSESession (cancels the stream goroutine) and WSSession (closes the socket)
    so probes can tear down the extra connection.
  • checks.go: route mcp-unauth-tools-list, mcp-resources-prompts-exposure, the
    OAuth Bearer-challenge check, and mcp-auth-posture through a separate
    anonymous session instead of WithNoAuth() on the authenticated one.
  • Finding-emitting probes run a full anonymous initialize first
    (anonymousInitializedSession): spec-compliant streamable-HTTP/SSE servers
    gate enumeration behind initialize + Mcp-Session-Id, so a fresh session that
    skipped it would under-report a genuinely open server (false negative).
  • authPostureProbe swaps to a fresh anonymous session while preserving its
    init-agnostic open/gated/unreached semantics; a refused anonymous connection
    now reads as gated rather than a false "open".

Tests: authenticated-WebSocket false-positive guard, initialize-gated open
streamable false-negative guard, and SSESession.Close.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

REAP's "unauthenticated exposure" probes re-used the session created with
--auth-header and merely suppressed the per-request Authorization header via
WithNoAuth(). That does not undo transport state established out-of-band:
WebSocket auth is bound to the upgrade handshake, streamable HTTP retains a
captured Mcp-Session-Id, and legacy SSE keeps an authenticated long-lived
stream. On WebSocket especially, WithNoAuth() is ignored entirely, so an
authenticated tool list could be reported as anonymous exposure (issue #1).

- Add AnonymousSession() to Session, SSESession and WSSession: a fresh,
  credential-free connection reusing the shared httpx.Client. Add Close() to
  SSESession (cancels the stream goroutine) and WSSession (closes the socket)
  so probes can tear down the extra connection.
- checks.go: route mcp-unauth-tools-list, mcp-resources-prompts-exposure, the
  OAuth Bearer-challenge check, and mcp-auth-posture through a separate
  anonymous session instead of WithNoAuth() on the authenticated one.
- Finding-emitting probes run a full anonymous initialize first
  (anonymousInitializedSession): spec-compliant streamable-HTTP/SSE servers
  gate enumeration behind initialize + Mcp-Session-Id, so a fresh session that
  skipped it would under-report a genuinely open server (false negative).
- authPostureProbe swaps to a fresh anonymous session while preserving its
  init-agnostic open/gated/unreached semantics; a refused anonymous connection
  now reads as gated rather than a false "open".

Tests: authenticated-WebSocket false-positive guard, initialize-gated open
streamable false-negative guard, and SSESession.Close.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hackwither
hackwither merged commit 054d25c into main Sep 4, 2026
3 checks passed
@hackwither
hackwither deleted the fix/anon-transport-state branch September 7, 2026 19:06
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.

1 participant