diff --git a/changelog.d/gst-1064-secrets-call-literal.md b/changelog.d/gst-1064-secrets-call-literal.md index 35c25132b..8c1596e9b 100644 --- a/changelog.d/gst-1064-secrets-call-literal.md +++ b/changelog.d/gst-1064-secrets-call-literal.md @@ -1,2 +1,2 @@ ### Fixed -- **The secrets check no longer reads a file name or dict key inside a call as a credential (GST-1064).** `key = json.loads(files.get("key.json", ""))` failed pregate with `PREGATE_SECRETS` (`env.kv`): eight distinct letters in `"key.json"` reach the entropy bar, so the call's argument looked like a secret. So did `token = resp.json().get("access_token")`. A call's first argument that is a lowercase file name or a snake_case key of two or three words now counts as a name. A later argument or fallback is still a value: `os.getenv("SECRET_KEY", "orange_monkey_pass")` and `.get("access_token", "")` still report. So do a real key in quotes or in a `.env` line, and a passphrase passed to a call (`decrypt("prod-signing-key")`). The entropy bar is unchanged. +- **The secrets check no longer reads a file name or dict key inside a call as a credential (GST-1064).** `key = json.loads(files.get("key.json", ""))` failed pregate with `PREGATE_SECRETS` (`env.kv`): eight distinct letters in `"key.json"` reach the entropy bar, so the call's argument looked like a secret. So did `token = resp.json().get("access_token")`. The first argument of a lookup call (`get`, `getenv`, `read`, `load`, `loads`, `open`, `pop`, `fetch`) that is a lowercase file name or a snake_case key of two or three words now counts as a name. Any other call still reports a password-shaped literal (`make_password("orange_monkey_pass")`, `bcrypt.hashpw(...)`), and so do a later argument or fallback (`os.getenv("SECRET_KEY", "orange_monkey_pass")`), a real key in quotes or in a `.env` line, and a kebab passphrase (`decrypt("prod-signing-key")`). The entropy bar is unchanged. diff --git a/lib/redact-patterns.ts b/lib/redact-patterns.ts index 56d93ad09..5bac73526 100644 --- a/lib/redact-patterns.ts +++ b/lib/redact-patterns.ts @@ -662,24 +662,26 @@ function isSchemaFieldIdentifier(span: string, match: RegExpExecArray): boolean return SCHEMA_FIELD_NAME.test(match[0]) && SCHEMA_FIELD_VALUE.test(span); } /** - * GST-1064: a call's first argument that is a lowercase file name + * GST-1064: the first argument of a lookup call (`get`, `getenv`, `read`, + * `load`, `loads`, `open`, `pop`, `fetch`) that is a lowercase file name * (`files.get("key.json")`) or a snake_case key of two or three words * (`resp.json().get("access_token")`) names what the call reads. Eight distinct * letters already reach 3.0 bits, so entropy alone cannot tell it from a - * secret. Only that first position is a lookup: a later argument or fallback - * (`os.getenv("X", "orange_monkey_pass")`, `.get("k") or "…"`) is a value and - * is still checked, and so is a first argument with a digit, an uppercase - * letter, kebab words or four or more snake_case words. + * secret. Any other callee (`make_password("orange_monkey_pass")`), a grouping + * paren, a later argument or a fallback (`os.getenv("X", "orange_monkey_pass")`) + * is a value and is still checked, and so is a first argument with a digit, an + * uppercase letter, kebab words or four or more snake_case words. */ const LOOKUP_ARGUMENT = - /\([ \t]*(["'])(?:[a-z]+(?:_[a-z]+){1,2}|[a-z]+(?:[_-][a-z]+)*\.(?:json|ya?ml|toml|ini|cfg|conf|env|pem|crt|cer|key|txt|csv|xml|cookie))\1/g; + /(?