From 1d5654ee107fb1da193d47587ad3d7c2b2293a6f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:09:58 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20Add=20ReadHeaderTimeout=20to=20http.Server=20instances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds `ReadHeaderTimeout` to all HTTP servers in OAuth login flows (`internal/provideroauth/openrouter.go`, `internal/oauth/loopback.go`, and `internal/mcp/oauth.go`) to prevent Slowloris attacks. Without `ReadHeaderTimeout`, a malicious client can open a connection and send request headers extremely slowly, keeping the connection alive and eventually exhausting server resources. Setting a reasonable timeout (e.g., 10 seconds) mitigates this vulnerability. Resolves Gosec G112 (CWE-400). Co-authored-by: euxaristia <25621994+euxaristia@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ internal/mcp/oauth.go | 1 + internal/oauth/loopback.go | 5 +++- internal/provideroauth/openrouter.go | 36 +++++++++++++++------------- 4 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 000000000..b0d4a27e2 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-08-14 - Fix Potential Slowloris Attack Vulnerability (G112) +**Vulnerability:** Found `http.Server` implementations missing `ReadHeaderTimeout` in `internal/provideroauth/openrouter.go`, `internal/oauth/loopback.go`, and `internal/mcp/oauth.go`. +**Learning:** By default, Go's `http.Server` does not have a timeout for reading the request headers. This allows malicious clients to keep connections open indefinitely by sending header data very slowly, leading to resource exhaustion (Slowloris attack). +**Prevention:** Always set `ReadHeaderTimeout` when initializing an `http.Server` instance. diff --git a/internal/mcp/oauth.go b/internal/mcp/oauth.go index 678d58045..e402e5e6a 100644 --- a/internal/mcp/oauth.go +++ b/internal/mcp/oauth.go @@ -409,6 +409,7 @@ func Login(ctx context.Context, options LoginOptions) (StoredToken, error) { } resultChan := make(chan callbackResult, 1) server := &http.Server{ + ReadHeaderTimeout: 10 * time.Second, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/callback" { http.NotFound(w, r) diff --git a/internal/oauth/loopback.go b/internal/oauth/loopback.go index 6b29e0f27..463e5d5be 100644 --- a/internal/oauth/loopback.go +++ b/internal/oauth/loopback.go @@ -50,7 +50,10 @@ func NewLoopbackListenerOnPort(state string, port int) (*LoopbackListener, error state: state, result: make(chan callbackResult, 1), } - l.server = &http.Server{Handler: http.HandlerFunc(l.handle)} + l.server = &http.Server{ + ReadHeaderTimeout: 10 * time.Second, + Handler: http.HandlerFunc(l.handle), + } go func() { _ = l.server.Serve(ln) }() return l, nil } diff --git a/internal/provideroauth/openrouter.go b/internal/provideroauth/openrouter.go index 8a99b3148..36321ebf0 100644 --- a/internal/provideroauth/openrouter.go +++ b/internal/provideroauth/openrouter.go @@ -79,26 +79,28 @@ func OpenRouterLogin(ctx context.Context, opts OpenRouterOptions) (string, error codeCh := make(chan string, 1) errCh := make(chan error, 1) - server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/callback" { - http.NotFound(w, r) - return - } - if code := strings.TrimSpace(r.URL.Query().Get("code")); code != "" { - _, _ = io.WriteString(w, "OpenRouter authorization complete. You may close this window.") + server := &http.Server{ + ReadHeaderTimeout: 10 * time.Second, + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/callback" { + http.NotFound(w, r) + return + } + if code := strings.TrimSpace(r.URL.Query().Get("code")); code != "" { + _, _ = io.WriteString(w, "OpenRouter authorization complete. You may close this window.") + select { + case codeCh <- code: + default: + } + return + } + w.WriteHeader(http.StatusBadRequest) + _, _ = io.WriteString(w, "Authorization failed. You may close this window.") select { - case codeCh <- code: + case errCh <- errors.New("provideroauth: callback missing authorization code"): default: } - return - } - w.WriteHeader(http.StatusBadRequest) - _, _ = io.WriteString(w, "Authorization failed. You may close this window.") - select { - case errCh <- errors.New("provideroauth: callback missing authorization code"): - default: - } - })} + })} go func() { _ = server.Serve(listener) }() defer func() { shutdownCtx, cancelShutdown := context.WithTimeout(context.Background(), time.Second) From 34008c375bb006e8ff76b51908fe236fd9bf638c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:22:37 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20Add=20ReadHeaderTimeout=20and=20update=20golang.org/x/image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes two issues: 1. Adds `ReadHeaderTimeout` to all HTTP servers in OAuth login flows (`internal/provideroauth/openrouter.go`, `internal/oauth/loopback.go`, and `internal/mcp/oauth.go`) to prevent Slowloris attacks (Gosec G112 / CWE-400). 2. Upgrades `golang.org/x/image` from v0.44.0 to v0.45.0 to resolve vulnerability GO-2026-6222 detected by govulncheck. Co-authored-by: euxaristia <25621994+euxaristia@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eb01e4a7f..47e9c2894 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/charmbracelet/x/term v0.2.2 github.com/coder/websocket v1.8.15 github.com/ledongthuc/pdf v0.0.0-20250511090121-5959a4027728 - golang.org/x/image v0.44.0 + golang.org/x/image v0.45.0 golang.org/x/sys v0.47.0 mvdan.cc/sh/v3 v3.13.1 ) diff --git a/go.sum b/go.sum index 745a1a09f..f32f72208 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M= golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY= -golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I= -golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY= +golang.org/x/image v0.45.0 h1:FMb1nTbH5H9vF55SriQHgFw5GnNL9Jg6L25BwXKzhB0= +golang.org/x/image v0.45.0/go.mod h1:n62x/7RqlwXDvGsSU4u6IUTUf6KghUZ9Bt7cG/T9Fx4= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=