🛡️ Sentinel: [MEDIUM] Fix missing HTTP client timeouts in OAuth

Replaced uses of standard `http.Post` and `http.PostForm` (which use the default `http.Client` with no timeout) in `pkg/auth/oauth.go` with an explicitly instantiated `http.Client` that includes a 15-second timeout.

This prevents the application from hanging indefinitely or exhausting resources if an external OAuth service is slow or unresponsive.

Also updated `.jules/sentinel.md` with this security learning.

Co-authored-by: hobbyistlabs-coder <267281733+hobbyistlabs-coder@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot] 2026-03-15 17:09:15 +00:00
parent a2c9e1ebcb
commit 8f07a434a3
2 changed files with 15 additions and 5 deletions

View file

@ -2,3 +2,8 @@
**Vulnerability:** Go's standard `http.ListenAndServe` and unconfigured `http.Server` instances lack default timeouts for reading headers, reading bodies, and writing responses.
**Learning:** These default settings leave the application vulnerable to resource exhaustion and Denial of Service (DoS) attacks, such as Slowloris, because malicious clients can slowly send data and tie up server connections indefinitely.
**Prevention:** Always instantiate `http.Server` explicitly and set `ReadHeaderTimeout`, `ReadTimeout`, `WriteTimeout`, and (optionally) `IdleTimeout` to reasonable values based on the expected request sizes and latencies.
## 2025-02-28 - [MEDIUM] Fix missing HTTP client timeouts in OAuth
**Vulnerability:** Go's standard `http.Post`, `http.PostForm`, `http.Get`, and the default `http.Client` do not have timeouts configured by default.
**Learning:** These defaults can leave the application vulnerable to resource exhaustion or indefinite hangs if the external service (like an OAuth provider) is slow, unresponsive, or experiencing an outage.
**Prevention:** Always instantiate `http.Client` explicitly with a sensible `Timeout` (e.g., `Timeout: 15 * time.Second`) before making outbound HTTP requests, instead of using the default package-level convenience functions.

View file

@ -208,7 +208,8 @@ func RequestDeviceCode(cfg OAuthProviderConfig) (*DeviceCodeInfo, error) {
"client_id": cfg.ClientID,
})
resp, err := http.Post(
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Post(
cfg.Issuer+"/api/accounts/deviceauth/usercode",
"application/json",
strings.NewReader(string(reqBody)),
@ -299,7 +300,8 @@ func LoginDeviceCode(cfg OAuthProviderConfig) (*AuthCredential, error) {
"client_id": cfg.ClientID,
})
resp, err := http.Post(
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Post(
cfg.Issuer+"/api/accounts/deviceauth/usercode",
"application/json",
strings.NewReader(string(reqBody)),
@ -358,7 +360,8 @@ func pollDeviceCode(cfg OAuthProviderConfig, deviceAuthID, userCode string) (*Au
"user_code": userCode,
})
resp, err := http.Post(
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Post(
cfg.Issuer+"/api/accounts/deviceauth/token",
"application/json",
strings.NewReader(string(reqBody)),
@ -410,7 +413,8 @@ func RefreshAccessToken(cred *AuthCredential, cfg OAuthProviderConfig) (*AuthCre
tokenURL = cfg.TokenURL
}
resp, err := http.PostForm(tokenURL, data)
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.PostForm(tokenURL, data)
if err != nil {
return nil, fmt.Errorf("refreshing token: %w", err)
}
@ -506,7 +510,8 @@ func ExchangeCodeForTokens(cfg OAuthProviderConfig, code, codeVerifier, redirect
provider = "google-antigravity"
}
resp, err := http.PostForm(tokenURL, data)
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.PostForm(tokenURL, data)
if err != nil {
return nil, fmt.Errorf("exchanging code for tokens: %w", err)
}