Skip to content

fix(auth): bind OAuth callback listener to loopback only - #6238

Open
SashaMIT wants to merge 1 commit into
stacklok:mainfrom
SashaMIT:fix/oauth-callback-loopback
Open

fix(auth): bind OAuth callback listener to loopback only#6238
SashaMIT wants to merge 1 commit into
stacklok:mainfrom
SashaMIT:fix/oauth-callback-loopback

Conversation

@SashaMIT

@SashaMIT SashaMIT commented Aug 7, 2026

Copy link
Copy Markdown

Anyone on the local network can cancel your ToolHive login while you are signing in.

Problem

The OAuth callback server used during interactive login binds :port (all interfaces) for the whole login flow, while the redirect URL it advertises is http://localhost:<port>/callback:

f.server = &http.Server{
    Addr:              fmt.Sprintf(":%d", f.port),
    Handler:           mux,
    ReadHeaderTimeout: 10 * time.Second,
}

Any host on the LAN can therefore reach the callback endpoint while a login is in progress and:

  • observe that a ToolHive login is happening, and
  • abort it by requesting /callback?error=access_denied (the error path does not require the state parameter) or by sending a wrong state.

Login-code theft is not possible: the 128-bit random state is validated before any token exchange, so an attacker cannot inject their own authorization code. The impact is an unauthenticated remote denial of service of interactive logins, plus an HTTP surface on every interface that has no reason to be reachable off-host.

Fix

Bind the listener to 127.0.0.1 explicitly via a small listenAddr() helper. This matches the redirect URL's localhost semantics and the loopback address the port-availability probe (networking.IsAvailable) already uses when selecting the callback port.

Tests

Added TestListenAddrLoopback, which asserts the listener address parses to a loopback IP on the flow's callback port. The pkg/auth/oauth, pkg/auth/tokensource, and pkg/auth/discovery suites pass.

Made with Cursor

The interactive login callback server bound ":port" (all interfaces)
while advertising a localhost redirect URL. For the lifetime of a
login, any host on the LAN could probe the listener and abort the
flow by hitting /callback?error=... (no state needed on the error
path). Login-code theft is not possible: the 128-bit state is
validated before token exchange, so the impact is login DoS only.

Bind 127.0.0.1 explicitly, matching the redirect URL host and the
loopback address the port-availability probe already uses. Added
TestListenAddrLoopback asserting the listener address is loopback.

Signed-off-by: Sasha Mitchell <sash.t.mitchell@gmail.com>
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