fix: Keep a numeric host:port address out of the unparseable branch - #886
Merged
Merged
Conversation
url.Parse rejects "127.0.0.1:8500" and "[::1]:8500": the first path segment cannot contain a colon, and a digit or "[" cannot begin a scheme. RedactURL treated any parse failure as "could be hiding a credential, replace it whole", so Consul's address -- whose default is exactly 127.0.0.1:8500 -- was reported in the status resource and the startup log as xxxxx, losing an address that holds no credential at all. Redis and DynamoDB addresses given as IP literals were affected the same way. Only a letter-starting host takes the scheme-plus-opaque path that parses, so the existing cases, consul.example.com:8500 and my-host, could not cover this. A value url.Parse rejects is now replaced whole only when it contains "@", "?" or "#". Those introduce the only components this function redacts: userinfo, a query, and a fragment. A value with none of them is a scheme, host, port and path, all of which are preserved when they do parse, so preserving them here is the same decision rather than a weaker one. This is a regression from 8.22.0: before that release RedactURL returned the input unchanged when parsing failed. No credential was exposed -- the failure is in the other direction, an operator losing the field's diagnostic value. Backport of the v9 fix in #879. Reported by Cursor Bugbot on that PR.
kinyoklion
approved these changes
Sep 21, 2026
kinyoklion
approved these changes
Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backport of the
v9fix in #879, for a regression that shipped in 8.22.0.url.Parserejects127.0.0.1:8500and[::1]:8500withfirst path segment in URL cannot contain colon: a digit or[cannot begin a scheme, and the first path segment cannot contain a colon.RedactURLtreated any parse failure as "could be hiding a credential, replace it whole", so the whole address becamexxxxx.Consul's default address is exactly that shape, so a default Consul deployment reports
in the unauthenticated status resource, and logs the same in its startup line. Redis and DynamoDB addresses given as IP literals are affected the same way.
Only a letter-starting host (
consul.example.com:8500,localhost:8500) parses -- as a scheme plus an opaque body -- which is why the existing cases could not cover this.No credential is exposed; the failure is in the other direction. An operator loses the diagnostic value of the field, and a support case reading
xxxxxcannot tell a redacted credential from a destroyed address. It is a regression rather than long-standing behavior: before #846,RedactURLreturned the input unchanged when parsing failed.Fix
A value
url.Parserejects is replaced whole only when it contains@,?or#. Those introduce the only components this function redacts: userinfo, a query, and a fragment. A value containing none of them is a scheme, host, port and path, all of which the function preserves when they do parse, so preserving them here is the same decision rather than a weaker one.redis://user:pass@127.0.0.1:not-a-portis still replaced whole, and so are unparseable values carrying a query or a fragment.Tests
internal/util/util_test.gogains127.0.0.1:8500,10.0.0.5:6379,[::1]:8500and192.168.1.1, plus three cases proving an unparseable value carrying@,?or#is still replaced whole. Each of the four new address cases returnsxxxxxon the shipped code, so they fail without this change.The
redactUnparseablehelper is byte-identical to the one onv9.Reported by Cursor Bugbot on #879. Its account of the mechanism described
url.URL.Stringinserting a./prefix, which is what happens to a relative path containing a colon; this input never reachesString, becauseParserefuses it first. The conclusion was right either way.Note
Overview
Fixes a 8.22.0 regression where
RedactURLreplaced unparseable strings entirely withxxxxx, so default Consul-style addresses like127.0.0.1:8500and[::1]:8500disappeared from status and logs even though they contain no credentials.On
url.Parsefailure, redaction now goes throughredactUnparseable: values with@,?, or#are still fully replaced (possible userinfo, query, or fragment); values without those characters are returned unchanged, matching the “preserve host/port/path” behavior used when parsing succeeds. Parsed-URL redaction is unchanged.Tests cover IP literal host:port, bare IPs, and unparseable strings that still must be fully redacted.
Reviewed by Cursor Bugbot for commit 0b2bd19. Bugbot is set up for automated code reviews on this repo. Configure here.