microcks / microcks/microcks-cli

Auth2 SSO Callback Server Is a Global Singleton, Race Condition & Port Hijack

Open
#312 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
52
Forks
68
Avg merge
6h 54m
Merged PRs (30d)
10

Description

### Describe the bug

The OAuth2 SSO Callback Server in the CLI (used during `login --sso`) acts as a global singleton due to its reliance on `http.DefaultServeMux`. This leads to race conditions and potential port hijacking vulnerabilities.

In `cmd/login.go:268-270` (approximate location):
```go
srv := &http.Server{Addr: "localhost:" + strconv.Itoa(port)}
http.HandleFunc("/auth/callback", callbackHandler)
```
This logic instantiates an `http.Server` but does not supply a dedicated `Handler`, meaning it falls back to the process-global `http.DefaultServeMux`. `http.HandleFunc` modifies this shared router, and this route is never cleaned up.

The critical impacts include:
1. **Port Hijacking / Token Exposure**: If a malicious process running locally on a multi-tenant machine binds to port 58085 first, the CLI's temporary HTTP server will fail to start (`log.Fatalf`), but the callback/authorization details from the user's browser may be successfully routed to the attacker. While PKCE prevents the attacker from directly exchanging the authorization code (as the `code_verifier` is in the memory of the CLI process), the `id_token` (passed as `r.FormValue("id_token")` in the fallback implicit flow) might be extracted directly by the attacking server.
2. **Global Mux Pollution & Race Conditions**: The URL handler `/auth/callback` persists permanently inside the process's default HTTP mux. If `login` is called twice (e.g., in a CI script, or if the first login fails midway), the subsequent calls overwrite the first handler. `http.HandleFunc` is not completely goroutine-safe when dynamically modifying the mux while a server handles requests. It can incorrectly interleave or fail across consecutive executions in the same process footprint.

### Expected behavior

1. A locally isolated `http.ServeMux` should be used per server instance instead of `http.DefaultServeMux`. For example:
```go
mux := http.NewServeMux()
mux.HandleFunc("/auth/callback", callbackHandler)
srv := &http.Server{
Addr: "localhost:" + strconv.Itoa(port),
Handler: mux,
}
```
2. The port binding error logic should be explicit: if the expected local port is already bound by another process, `login()` should abort safely and alert the user immediately, rather than quietly failing inside a goroutine or leaving the user vulnerable to authorization route hijacking.

### Actual behavior

The `http.HandleFunc` manipulates the global `http.DefaultServeMux`. The CLI process could leak handlers or have subsequent authentication operations overwrite global states over one another.

### How to Reproduce?

1. Open a separate terminal and mock an attacker process by listening on port 58085:
```bash
nc -l -p 58085
```
2. Run the `microcks-cli login --sso` command.
3. Observe that the OAuth authentication flow continues locally.
4. When the browser redirects to `http://localhost:58085/auth/callback...`, the attacker `nc` instance intercepts the HTTP request, collecting the query parameters (which may contain `code` or `id_token` depending on the SSO provider mapping configuration).

Alternatively, inspecting the source code validates the reliance on `http.DefaultServeMux`:
1. Find `srv := &http.Server{Addr: "localhost:" + strconv.Itoa(port)}` inside `cmd/login.go`.
2. Notice that `http.HandleFunc` is being used, making `/auth/callback` globally registered on `http.DefaultServeMux`.

### Microcks version or git rev

microcks-cli2 (Current main/issue-branch code base as of reported date)

### Install method (`docker-compose`, `helm chart`, `operator`, `docker-desktop extension`,...)

Compiled from source (`go build`)

### Additional information

This issue affects multi-tenant environments where CI/CD setups or shared developer workstations might have concurrent or conflicting listeners. Fixing the HTTP handler scoping provides a resilient boundary.

Contributor guide

Open the contributing guide

Research direction

Start in cmd/login.go around lines 268-270 and trace the login --sso callback server startup and error path. Verify how the server uses http.DefaultServeMux and how a port-binding failure is handled. Done means each server has isolated routing and an occupied local port causes login to abort clearly; exercise the supplied nc reproduction and relevant CLI flows.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
authentication, cli, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.