Skip to content

DataProviderMigrate logs full connection string (including password) to stdout — severe credential leak #62

@MelbourneDeveloper

Description

@MelbourneDeveloper

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:

  1. Parse the connection string with NpgsqlConnectionStringBuilder.
  2. Replace Password, SSL Password, Passfile, and any other secret-bearing keys with ***.
  3. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions