mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 14:06:50 +01:00
H #2913: postgres:postgres is exempt only on a loopback host
The postgres image's default pair in compose files and CI DATABASE_URLs blocked pushes as db.url_with_password HIGH. It is now exempt only for postgres/postgresql URLs with exactly postgres:postgres on localhost or 127.0.0.1 (optional port). A bare single-label host (`db`, `postgres`), any other host, a host that merely starts with localhost (`localhost.evil...`, `localhost@prod-db`), any other user or password, and other schemes still block. #2913 exempted the pair on any host; this keeps the plan's narrower rule. Co-authored-by: mb1810 <michael.berger1810@gmail.com>
This commit is contained in:
1 parent
5999ee3bad
commit
178724034b
2 files changed
+46
-2
No files matched your search
+15
-2
@@ -521,6 +521,18 @@ function urlPasswordIsPlaceholder(span: string): boolean {
|
||||
return PLACEHOLDER_STRUCTURAL.some((re) => re.test(pw));
|
||||
}
|
||||
|
||||
/**
|
||||
* #2913: `postgres:postgres` is the official postgres image's default pair,
|
||||
* committed in compose files and CI DATABASE_URLs. It is exempt only on a
|
||||
* loopback host (`localhost` or `127.0.0.1`, optional port), never on a
|
||||
* single-label host such as `db`: a compose service name says nothing about
|
||||
* where the same URL is also deployed, and a weak default on a reachable host
|
||||
* is exactly the leak to report. Exact user and password, case-sensitive;
|
||||
* the host must end at a port, path, query, quote or the span's end.
|
||||
*/
|
||||
const POSTGRES_LOOPBACK_DEFAULT =
|
||||
/^postgres(?:ql)?:\/\/postgres:postgres@(?:localhost|127\.0\.0\.1)(?::\d{1,5})?(?![\w.:@%-])/;
|
||||
|
||||
/** A value span that is only an environment-variable read expression (#2912). */
|
||||
const ENV_READ_SPAN =
|
||||
/^(?:os\.environ\[|os\.environ\.get\(|os\.getenv\(|getenv\(|ENV\[|process\.env\.[A-Za-z_$][\w$]*[;,)]?)$/;
|
||||
@@ -767,8 +779,9 @@ export const PATTERNS: RedactPattern[] = [
|
||||
category: "secret",
|
||||
description: "Database URL with embedded password",
|
||||
regex: /\b((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp):\/\/[^:\s/@]+:[^@\s/]+@[^\s/]+)/,
|
||||
// Skip when the password segment is itself a placeholder/interpolation.
|
||||
validate: (span) => !urlPasswordIsPlaceholder(span),
|
||||
// Skip when the password segment is itself a placeholder/interpolation,
|
||||
// or the URL is postgres's default pair on a loopback host.
|
||||
validate: (span) => !urlPasswordIsPlaceholder(span) && !POSTGRES_LOOPBACK_DEFAULT.test(span),
|
||||
},
|
||||
{
|
||||
id: "creds.basic_auth_url",
|
||||
|
||||
@@ -160,3 +160,34 @@ describe("pii.ip_public: a four-part version needs a version declaration (#2784)
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
describe("db.url_with_password: postgres:postgres only on a loopback host (#2913)", () => {
|
||||
// Assembled from parts so this file's own source never carries a
|
||||
// credential-bearing URL for the repo's secret scan to block.
|
||||
const url = (userinfo: string, rest: string, scheme = "postgresql") => `${scheme}://${userinfo}@${rest}`;
|
||||
const pg = ["postgres", "postgres"].join(":");
|
||||
table(
|
||||
"db.url_with_password",
|
||||
"HIGH",
|
||||
[
|
||||
`DATABASE_URL=${url(pg, "localhost:5432/app_test")}`,
|
||||
`DATABASE_URL=${url(pg, "127.0.0.1:5432/app", "postgres")}`,
|
||||
`DIRECT_URL="${url(pg, "localhost/app")}"`,
|
||||
`url: ${url(pg, "localhost", "postgres")}`,
|
||||
url(pg, "localhost:5432?sslmode=disable"),
|
||||
],
|
||||
[
|
||||
`DATABASE_URL=${url(pg, "db:5432/app")}`,
|
||||
`DATABASE_URL=${url(pg, "postgres:5432/app")}`,
|
||||
`DATABASE_URL=${url(pg, "prod-host:5432/app")}`,
|
||||
`DATABASE_URL=${url(pg, "localhost.evil.example.net/app")}`,
|
||||
`DATABASE_URL=${url(pg, "127.0.0.1.nip.io/app")}`,
|
||||
`DATABASE_URL=${url(pg, "localhost@prod-db/app")}`,
|
||||
`DATABASE_URL=${url(["user", "s3cretPassw0rd"].join(":"), "prod-host:5432/app")}`,
|
||||
`DATABASE_URL=${url(["postgres", "hunter2x"].join(":"), "localhost:5432/app")}`,
|
||||
`DATABASE_URL=${url(["admin", "postgres"].join(":"), "localhost:5432/app")}`,
|
||||
`DATABASE_URL=${url(["postgres", "Postgres"].join(":"), "localhost:5432/app")}`,
|
||||
`DATABASE_URL=${url(pg, "localhost:3306/app", "mysql")}`,
|
||||
],
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user