Skip to content

Commit 1f87a77

Browse files
appleboyclaude
andcommitted
fix(main): address medium-severity security findings
- Bound HTTP response reads to 1 MB via io.LimitReader to prevent unbounded memory allocation - Replace configInitialized bool with sync.Once to eliminate potential data race - Warn when client secret is passed via CLI flag as it may be visible in process listings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9bc1791 commit 1f87a77

1 file changed

Lines changed: 27 additions & 20 deletions

File tree

main.go

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os/signal"
1515
"strconv"
1616
"strings"
17+
"sync"
1718
"syscall"
1819
"time"
1920

@@ -28,18 +29,18 @@ import (
2829
)
2930

3031
var (
31-
serverURL string
32-
clientID string
33-
clientSecret string
34-
redirectURI string
35-
callbackPort int
36-
scope string
37-
tokenFile string
38-
tokenStoreMode string
39-
tokenStore credstore.Store[credstore.Token]
40-
configInitialized bool
41-
retryClient *retry.Client
42-
configWarnings []string
32+
serverURL string
33+
clientID string
34+
clientSecret string
35+
redirectURI string
36+
callbackPort int
37+
scope string
38+
tokenFile string
39+
tokenStoreMode string
40+
tokenStore credstore.Store[credstore.Token]
41+
configOnce sync.Once
42+
retryClient *retry.Client
43+
configWarnings []string
4344

4445
flagServerURL *string
4546
flagClientID *string
@@ -55,6 +56,7 @@ const (
5556
tokenExchangeTimeout = 10 * time.Second
5657
tokenVerificationTimeout = 10 * time.Second
5758
refreshTokenTimeout = 10 * time.Second
59+
maxResponseSize = 1 << 20 // 1 MB
5860
)
5961

6062
func init() {
@@ -96,16 +98,21 @@ func init() {
9698

9799
// initConfig parses flags and initializes all configuration.
98100
func initConfig() {
99-
if configInitialized {
100-
return
101-
}
102-
configInitialized = true
101+
configOnce.Do(doInitConfig)
102+
}
103103

104+
func doInitConfig() {
104105
flag.Parse()
105106

106107
serverURL = getConfig(*flagServerURL, "SERVER_URL", "http://localhost:8080")
107108
clientID = getConfig(*flagClientID, "CLIENT_ID", "")
108109
clientSecret = getConfig(*flagClientSecret, "CLIENT_SECRET", "")
110+
if *flagClientSecret != "" {
111+
configWarnings = append(configWarnings,
112+
"Client secret passed via command-line flag. "+
113+
"This may be visible in process listings. "+
114+
"Consider using CLIENT_SECRET env var or .env file instead.")
115+
}
109116
scope = getConfig(*flagScope, "SCOPE", "read write")
110117
tokenFile = getConfig(*flagTokenFile, "TOKEN_FILE", ".authgate-tokens.json")
111118

@@ -341,7 +348,7 @@ func exchangeCode(ctx context.Context, code, codeVerifier string) (*tui.TokenSto
341348
}
342349
defer resp.Body.Close()
343350

344-
body, err := io.ReadAll(resp.Body)
351+
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
345352
if err != nil {
346353
return nil, fmt.Errorf("failed to read response: %w", err)
347354
}
@@ -405,7 +412,7 @@ func refreshAccessToken(ctx context.Context, refreshToken string) (*tui.TokenSto
405412
}
406413
defer resp.Body.Close()
407414

408-
body, err := io.ReadAll(resp.Body)
415+
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
409416
if err != nil {
410417
return nil, fmt.Errorf("failed to read response: %w", err)
411418
}
@@ -472,7 +479,7 @@ func verifyToken(ctx context.Context, accessToken string) (string, error) {
472479
}
473480
defer resp.Body.Close()
474481

475-
body, err := io.ReadAll(resp.Body)
482+
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
476483
if err != nil {
477484
return "", fmt.Errorf("failed to read response: %w", err)
478485
}
@@ -531,7 +538,7 @@ func makeAPICallWithAutoRefresh(ctx context.Context, storage *tui.TokenStorage)
531538
defer resp.Body.Close()
532539
}
533540

534-
body, err := io.ReadAll(resp.Body)
541+
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
535542
if err != nil {
536543
return fmt.Errorf("failed to read response: %w", err)
537544
}

0 commit comments

Comments
 (0)