Skip to content

migrate-db: redact credentials from the postgres DSN in logs - #101

Merged
Roasbeef merged 1 commit into
lightninglabs:mainfrom
djkazic:fix-postgres-dsn-log-leak
Sep 19, 2026
Merged

Roasbeef merged 1 commit into
lightninglabs:mainfrom
djkazic:fix-postgres-dsn-log-leak

Conversation

@djkazic

@djkazic djkazic commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

migrate-db logs the destination postgres DSN verbatim, and the DSN is where
the database password lives:

[INF] LNDINIT Opening postgres backend at `postgres://lnd:hunter2@postgres:5432/lnd?sslmode=disable` with prefix `channeldb`

The line is at info level, which is what -v selects since #98; before that PR
-v set the level to error and kept the password out of stderr. In the k8s
setup lndinit is built for, stderr is the pod log.

The line predates #98 and the handler defaults to info, so an invocation with no
flags at all printed the DSN before as well. Fixing the log line covers both
paths, which is why this doesn't touch the -v change.

redactDsn keeps only the parameters known not to hold a secret and drops
everything else, rather than hunting for the ones that do: a blocklist that is
wrong once prints the password, an allow list that is wrong just prints less.
A DSN that doesn't parse is replaced wholesale. Both notations pgx accepts are
handled, since a password can sit in the userinfo section, in a query parameter
or in a password= field:

DSN logged as
postgres://alice:s3cr3t@localhost:5432/lnd?sslmode=disable postgres://alice@localhost:5432/lnd?sslmode=disable
postgres://alice@localhost:5432/lnd?password=s3cr3t postgres://alice@localhost:5432/lnd
host=localhost user=alice password=s3cr3t dbname=lnd host=localhost user=alice dbname=lnd
postgres://alice:s3cr3t@loc alhost/lnd [redacted]

Host, port, database and user survive, which is what the line is there for.

TestRedactDsn covers each notation, the three hiding places, an unparsable DSN
and a quoted value with spaces, asserting on every case that the password
appears nowhere in the output. The other logger.Info sites log secret names,
not values, so this was the only one the level change widened.

@djkazic
djkazic requested a review from Roasbeef September 17, 2026 14:32
@djkazic djkazic self-assigned this Sep 17, 2026
openDestDb logs the destination postgres DSN verbatim, and the DSN is
where the database password lives. The line is logged at info level,
which since lightninglabs#98 is what `-v` selects: before that commit `-v` set the
level to `error`, so the documented verbose invocation kept the password
out of stderr. It doesn't anymore, and in the k8s setup lndinit is meant
for, stderr is the pod log.

Rather than looking for the parts of a DSN that are known to be
sensitive, we keep only the ones that are known not to be. A connection
string we fail to fully understand must not leak a password, so anything
outside the allow list is dropped, and a DSN we can't parse at all is
replaced wholesale. Both notations postgres accepts are handled, the URL
one and the keyword/value one, since a password can hide in the userinfo
section, in a query parameter or in a `password=` field.
@djkazic
djkazic force-pushed the fix-postgres-dsn-log-leak branch from f280908 to 851d251 Compare September 17, 2026 14:34

@Roasbeef Roasbeef left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@Roasbeef
Roasbeef merged commit a11c50d into lightninglabs:main Sep 19, 2026
2 checks passed
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