Skip to content

fix: Redact all credential-bearing URL components in the status dbServer field - #879

Merged
keelerm84 merged 2 commits into
v9from
mk/SDK-3155/redact-db-server
Sep 21, 2026
Merged

keelerm84 merged 2 commits into
v9from
mk/SDK-3155/redact-db-server

Conversation

@keelerm84

@keelerm84 keelerm84 commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Summary

util.RedactURL only replaced a password inside a URL's userinfo, and returned an unparseable URL verbatim. ConfigureDataStore then published the Consul host and the DynamoDB endpoint URL into DBServer without redacting either. The status resource is unauthenticated, so a secret in the username position, in a query parameter, or in a fragment was exposed.

RedactURL now replaces the userinfo, query and fragment independently, each only when it is present, and replaces a URL entirely when it cannot be parsed. Two shapes needed care:

  • A non-hierarchical scheme:rest URL keeps everything, userinfo included, in URL.Opaque. The config layer accepts these, since url.IsAbs is true, so a missing // must not publish the credential verbatim. Only the part up to the last @ is redacted.
  • url.Parse also reports a bare host:port as a scheme plus an opaque body, and Consul's dbServer is exactly that shape, so redacting the whole opaque body would destroy the port.

The scheme, host, port and path survive so the result stays useful for diagnostics. The path is deliberately preserved, which means the result is not safe for a URL that embeds a credential in a path segment; docs/endpoints.md states that limitation rather than leaving it implied.

The Consul store itself still receives the real address. Only the displayed copy is redacted.

This brings v9 to parity with v8 #846.

Not affected

  • internal/httpconfig/httpconfig.go redacts its proxy URL with url.Redacted() directly rather than util.RedactURL, so its behavior and its test expectations are unchanged.
  • internal/sdks/big_segments.go is a third RedactURL caller that benefits automatically; it had no redaction assertions to update.
  • integrationtests/database_params_test.go needs no change: its DBServer expectations use Consul and DynamoDB addresses that carry no credentials, so redaction is a no-op there.

Note

Overview
Strengthens URL redaction so secrets are not exposed on the unauthenticated /status dataStoreStatus.dbServer field (and related logs).

util.RedactURL now replaces userinfo, query, and fragment with xxxxx (not only passwords), handles unparseable URLs and scheme:opaque shapes, and keeps host/port/path for diagnostics—with a documented exception that path segments are not redacted. ConfigureDataStore applies this to Consul hosts and DynamoDB endpoint URLs in status info and Info logs; Redis expectations/tests now cover username-only secrets and query/fragment redaction. Docs describe the redaction rules for dbServer.

Reviewed by Cursor Bugbot for commit 3e58558. Bugbot is set up for automated code reviews on this repo. Configure here.

@keelerm84
keelerm84 force-pushed the mk/SDK-3155/redact-db-server branch from b18abbd to 04b53bc Compare September 18, 2026 20:23
@keelerm84
keelerm84 marked this pull request as ready for review September 18, 2026 20:32
@keelerm84
keelerm84 requested a review from a team as a code owner September 18, 2026 20:32

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 04b53bc. Configure here.

Comment thread internal/util/util.go
keelerm84 added a commit that referenced this pull request Sep 21, 2026
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.

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.

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 does not reach String at all, because Parse
refuses it first. The conclusion was right either way.
…ver field

RedactURL only replaced a password inside a URL's userinfo, and returned an
unparseable URL verbatim. ConfigureDataStore then published the Consul host and
the DynamoDB endpoint URL into DBServer without redacting either. The status
resource is unauthenticated, so a secret in the username position, in a query
parameter, or in a fragment was exposed.

RedactURL now replaces the userinfo, query and fragment independently, each only
when present, and replaces a URL entirely when it cannot be parsed. It handles
the non-hierarchical "scheme:rest" shape, whose userinfo lands in URL.Opaque,
and preserves a bare "host:port" so Consul's address keeps its port. The scheme,
host, port and path survive so the result stays useful for diagnostics.

The path is deliberately preserved, so the result is not safe for a URL that
embeds a credential in a path segment. docs/endpoints.md states that limitation.

The Consul store still receives the real address; only the displayed copy is
redacted.
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.

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.

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 does not reach String at all, because Parse
refuses it first. The conclusion was right either way.
@keelerm84
keelerm84 force-pushed the mk/SDK-3155/redact-db-server branch from 9e6b75f to 3e58558 Compare September 21, 2026 19:07
@keelerm84
keelerm84 merged commit 73b253d into v9 Sep 21, 2026
16 checks passed
@keelerm84
keelerm84 deleted the mk/SDK-3155/redact-db-server branch September 21, 2026 20:39
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