All rules Rule BC003 · PC
Credential rule · any database
critical
PC · Privileges & credentials
also runs on any file, bolvrk secrets
free in the CLI

What happens when a connection string with a password is committed?

Connection string with an embedded password in a string literal

Critical: a working credential committed to the repository; rotate it, git history keeps it.

What happens

A DSN like postgres://app:hunter2@db.internal/app or host=… password=… seeded into a settings row, a column DEFAULT, or a dblink() call is a live credential in a committed file. It is also the one that spreads furthest, a DSN in a settings table is read by every service that loads settings. Only fires when the string parses as a libpq-style URI or keyword string with a non-empty, non-placeholder password.

Why it is dangerous on a populated table

Table size does not change this one: a committed credential is live from the first row, and git history keeps it after the fix.

Fires on

INSERT INTO integrations (name, dsn) VALUES ('warehouse', 'postgres://etl:hunter2@warehouse.internal:5432/dw');

The safe pattern

Store the DSN without the password and let the service resolve it at runtime from its secret store, or seed a placeholder the deploy substitutes. Both forms stay silent: a URI with no password, or an env-style slot in its place.

INSERT INTO integrations (name, dsn) VALUES ('warehouse', 'postgres://etl@warehouse.internal:5432/dw');
-- the service reads PGPASSWORD / a passfile at runtime

Fixtures

The rule ships with these files and the test suite runs them on every change: the first set must fire, the second must stay silent.

Fires (4)

dblink conninfo
SELECT dblink_connect('reports', 'host=reports.internal dbname=reports user=etl password=etl-pw-2026');
default keyword conninfo
ALTER TABLE tenants ADD COLUMN reporting_dsn text DEFAULT 'host=reports.internal dbname=reports user=tenant password=tenant-default-pw';
insert uri
INSERT INTO integrations (name, dsn) VALUES ('warehouse', 'postgres://etl:hunter2@warehouse.internal:5432/dw');
update redis url
UPDATE settings SET value = 'redis://default:cache-pass-2026@cache.internal:6379/0' WHERE key = 'cache_url';

Stays silent (4)

keyword without password
SELECT dblink_connect('reports', 'host=reports.internal dbname=reports user=etl sslmode=verify-full');
plain urls and emails
INSERT INTO settings (key, value) VALUES ('webhook_url', 'https://hooks.example.com/orders'), ('support_email', 'support@example.com'), ('docs', 'https://example.com/docs?user=guest');
uri env placeholder
INSERT INTO integrations (name, dsn) VALUES ('warehouse', 'postgres://etl:${WAREHOUSE_PASSWORD}@warehouse.internal:5432/dw');
uri without password
INSERT INTO integrations (name, dsn) VALUES ('warehouse', 'postgres://etl@warehouse.internal:5432/dw?sslmode=require');

How to check locally

Catch this before it ships

This rule runs locally in the free CLI, or with the full corpus through the hosted service. No install, nothing leaves your machine:

npx bolvrk check migration.sql