From 8a47689fb2d7192719d7329bdce26f51f5119a0d Mon Sep 17 00:00:00 2001 From: Nishad Mathur Date: Wed, 21 Oct 2026 13:28:25 -0700 Subject: [PATCH] Reject colons in HTTP agent usernames before hashing Fail early when an HTTPS mbus username contains a decoded colon, since Basic Auth treats it as the username/password separator. Return a credential-free error before creating an unusable password verifier. Add a regression test covering a percent-encoded colon in the username. ai-assisted=yes TNZ-129825 --- agentpassword/agentpassword.go | 3 +++ agentpassword/agentpassword_test.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/agentpassword/agentpassword.go b/agentpassword/agentpassword.go index 03fc7b55a..4493bf1a7 100644 --- a/agentpassword/agentpassword.go +++ b/agentpassword/agentpassword.go @@ -72,6 +72,9 @@ func HashURL(raw string) (string, error) { if u.User == nil { return "", errors.New("URL missing userinfo") } + if strings.Contains(u.User.Username(), ":") { + return "", errors.New("URL username must not contain a colon") + } password, hasPassword := u.User.Password() if !hasPassword || password == "" { return "", errors.New("URL missing password") diff --git a/agentpassword/agentpassword_test.go b/agentpassword/agentpassword_test.go index c8b21bb6b..ee76eac0a 100644 --- a/agentpassword/agentpassword_test.go +++ b/agentpassword/agentpassword_test.go @@ -120,6 +120,13 @@ var _ = Describe("Agentpassword", func() { }) Describe("HashURL", func() { + It("rejects a colon in the decoded username without exposing credentials", func() { + raw := "https://user%3Aextra:secret-password@127.0.0.1:6868" + hashed, err := agentpassword.HashURL(raw) + Expect(err).To(MatchError("URL username must not contain a colon")) + Expect(hashed).To(BeEmpty()) + }) + It("performs a complete HashURL -> ParseHashedPassword -> Matches round trip", func() { raw := "https://vcap:mypassword@127.0.0.1:6868/path?foo=bar#frag" hashed, err := agentpassword.HashURL(raw)