Summary
DataProviderMigrate migrate (v0.9.12-beta, but reproduced across at least 0.9.11/0.9.12) prints the full Npgsql connection string — including the cleartext password — to stdout as part of its startup banner:
DataProviderMigrate - Database Schema Tool
Schema: migrations/schema.yaml
Output: Host=...;Port=5432;Database=postgres;Username=postgres.<project_ref>;Password=<CLEARTEXT PASSWORD>;SslMode=Require;Trust Server Certificate=true
Provider: postgres
Impact
This is a severe credential exfiltration vector:
- CI logs (GitHub Actions, Cloud Build, GitLab CI, etc.) capture stdout by default — every prod migration run pastes the DB password into a log file that may be retained for weeks, shared with contractors, ingested by log-aggregation tooling, and is one mis-set retention policy away from a public leak.
- Operator terminals + shared screens (pair sessions, support calls, screen recordings) expose the password to anyone viewing the live output.
- AI agent transcripts (Claude Code, Copilot Workspace, etc.) — running migrations from inside an agent session writes the password into the conversation transcript, which often ends up in third-party storage out of the operator's control.
- Caller stdout capture — the consuming repo's
Makefile / shell scripts that pipe migration output to log files inherit the leak with no opt-out.
We just leaked a production Supabase Postgres password in two separate places (shell + tool output) during routine migration work, despite never explicitly reading .env. The credential was rotated immediately, but the cost of one careless pipe is a prod compromise.
Repro
Any invocation of DataProviderMigrate migrate --output <DSN> --schema <schema> --provider postgres where the DSN contains Password=….
Expected
Banner should redact the password component (and any other sensitive options like Integrated Security, Passfile, SSL Key Password, etc.) before printing. A standard approach:
- Parse the connection string with
NpgsqlConnectionStringBuilder.
- Replace
Password, SSL Password, Passfile, and any other secret-bearing keys with ***.
- Re-emit via
builder.ConnectionString.
Better: don't log the connection string at all. The host/db/user are useful for operator confirmation; the password never is.
Suggested fix
static string RedactConnectionString(string raw)
{
var b = new NpgsqlConnectionStringBuilder(raw);
if (!string.IsNullOrEmpty(b.Password)) b.Password = "***";
// and any other secret keys NpgsqlConnectionStringBuilder exposes
return b.ConnectionString;
}
Workaround callers can apply today
None at the tool layer — the tool itself emits the leak. Wrappers can 2>/dev/null the migration output, but that also hides genuine errors. The only safe interim option is to scrub stdout in the calling Makefile / pipeline (e.g. | sed -E 's/Password=[^;]*/Password=***/g'), which is fragile and prone to footguns when the connection-string syntax changes.
Priority
This is a security defect, not a UX nit. Suggest treating it as such — fix in the next patch release and consider mentioning in release notes so operators can grep their CI logs for the format and rotate accordingly.
Repro environment
- Tool:
DataProviderMigrate 0.9.12-beta
- Caller:
nap repo make migrate (passes DSN via --output)
- Database: Supabase Postgres (pooler endpoint)
Summary
DataProviderMigrate migrate(v0.9.12-beta, but reproduced across at least 0.9.11/0.9.12) prints the full Npgsql connection string — including the cleartext password — to stdout as part of its startup banner:Impact
This is a severe credential exfiltration vector:
Makefile/ shell scripts that pipe migration output to log files inherit the leak with no opt-out.We just leaked a production Supabase Postgres password in two separate places (shell + tool output) during routine migration work, despite never explicitly reading
.env. The credential was rotated immediately, but the cost of one careless pipe is a prod compromise.Repro
Any invocation of
DataProviderMigrate migrate --output <DSN> --schema <schema> --provider postgreswhere the DSN containsPassword=….Expected
Banner should redact the password component (and any other sensitive options like
Integrated Security,Passfile,SSL Key Password, etc.) before printing. A standard approach:NpgsqlConnectionStringBuilder.Password,SSL Password,Passfile, and any other secret-bearing keys with***.builder.ConnectionString.Better: don't log the connection string at all. The host/db/user are useful for operator confirmation; the password never is.
Suggested fix
Workaround callers can apply today
None at the tool layer — the tool itself emits the leak. Wrappers can
2>/dev/nullthe migration output, but that also hides genuine errors. The only safe interim option is to scrub stdout in the calling Makefile / pipeline (e.g.| sed -E 's/Password=[^;]*/Password=***/g'), which is fragile and prone to footguns when the connection-string syntax changes.Priority
This is a security defect, not a UX nit. Suggest treating it as such — fix in the next patch release and consider mentioning in release notes so operators can grep their CI logs for the format and rotate accordingly.
Repro environment
DataProviderMigrate 0.9.12-betanaprepomake migrate(passes DSN via--output)