microcks / microcks/microcks-cli
Auth2 SSO Callback Server Is a Global Singleton, Race Condition & Port Hijack
- 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
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