diff --git a/internal/secureenv/manager.go b/internal/secureenv/manager.go index ab3b08f7..1f5b4208 100644 --- a/internal/secureenv/manager.go +++ b/internal/secureenv/manager.go @@ -342,6 +342,10 @@ func anyProxyKeyPresent(present map[string]struct{}, group []string) bool { // proxy host/port so the proxy remains functional. Non-URL values (e.g. the // host list in NO_PROXY) and unparseable values are returned unchanged. func redactProxyCredentials(value string) string { + // Surrounding whitespace would make url.Parse error (leading space) or + // otherwise fall through, forwarding a credentialed value verbatim. Trim it + // first; whitespace is never meaningful in a proxy URL. + value = strings.TrimSpace(value) if value == "" { return value } diff --git a/internal/secureenv/proxy_forward_test.go b/internal/secureenv/proxy_forward_test.go index 07a36dd9..210b9ef6 100644 --- a/internal/secureenv/proxy_forward_test.go +++ b/internal/secureenv/proxy_forward_test.go @@ -36,6 +36,11 @@ func TestRedactProxyCredentials(t *testing.T) { {"schemeless user only", "user@proxy.example.com:3128", "proxy.example.com:3128"}, {"schemeless no userinfo", "proxy.example.com:8080", "proxy.example.com:8080"}, {"schemeless at-in-path not stripped", "proxy.example.com:8080/path@x", "proxy.example.com:8080/path@x"}, + // Whitespace-wrapped credentialed URLs would otherwise make url.Parse + // error and fall through, forwarding creds verbatim (PR #704 non-blocking + // review note). Surrounding whitespace is trimmed before redaction. + {"whitespace-wrapped scheme creds", " http://user:pass@proxy.example.com:8080 ", "http://proxy.example.com:8080"}, + {"whitespace-wrapped schemeless creds", "\tuser:pass@proxy.example.com:8080\n", "proxy.example.com:8080"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) {