Skip to content

fix: Keep a numeric host:port address out of the unparseable branch - #886

Merged
keelerm84 merged 1 commit into
v8from
mk/SDK-3163/redact-numeric-host-port
Sep 21, 2026
Merged

keelerm84 merged 1 commit into
v8from
mk/SDK-3163/redact-numeric-host-port

Conversation

@keelerm84

@keelerm84 keelerm84 commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Summary

Backport of the v9 fix in #879, for a regression that shipped in 8.22.0.

url.Parse rejects 127.0.0.1:8500 and [::1]:8500 with first path segment in URL cannot contain colon: a digit or [ cannot begin a scheme, and the first path segment cannot contain a colon. RedactURL treated any parse failure as "could be hiding a credential, replace it whole", so the whole address became xxxxx.

Consul's default address is exactly that shape, so a default Consul deployment reports

"dbServer": "xxxxx"

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 xxxxx cannot tell a redacted credential from a destroyed address. It is a regression rather than long-standing behavior: before #846, RedactURL returned the input unchanged when parsing failed.

Fix

A value url.Parse rejects 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-port is still replaced whole, and so are unparseable values carrying a query or a fragment.

Tests

internal/util/util_test.go gains 127.0.0.1:8500, 10.0.0.5:6379, [::1]:8500 and 192.168.1.1, plus three cases proving an unparseable value carrying @, ? or # is still replaced whole. Each of the four new address cases returns xxxxx on the shipped code, so they fail without this change.

The redactUnparseable helper is byte-identical to the one on v9.

Reported by Cursor Bugbot on #879. Its account of the mechanism described url.URL.String inserting a ./ prefix, which is what happens to a relative path containing a colon; this input never reaches String, because Parse refuses it first. The conclusion was right either way.


Note

Overview
Fixes a 8.22.0 regression where RedactURL replaced unparseable strings entirely with xxxxx, so default Consul-style addresses like 127.0.0.1:8500 and [::1]:8500 disappeared from status and logs even though they contain no credentials.

On url.Parse failure, redaction now goes through redactUnparseable: 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.

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.
@keelerm84
keelerm84 requested a review from a team as a code owner September 21, 2026 17:26
@keelerm84
keelerm84 merged commit bbdfd9c into v8 Sep 21, 2026
18 checks passed
@keelerm84
keelerm84 deleted the mk/SDK-3163/redact-numeric-host-port branch September 21, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants