Env-key extraction safety — the prefix-collision rule
Origin: incident #3494 (2026-07-09). A Tier-1 MongoDB rs0 admin credential was exposed in
visible session output while extracting a value from a dotenv-style file during the #3171 SOPS-drift
fix. The credential was rotated the same day (PR #3513) — this playbook is the durable prevention
(root-cause follow-up item 3: “a corrected, anchored extraction pattern that cannot suffer this
substring-collision bug again”).
What went wrong
The extraction used an unanchored grep:
# ❌ WRONG — unanchored: matches every line that CONTAINS the substring
grep 'MONGODB_URL=' backend-environment.envPMONGODB_URL= contains MONGODB_URL= as a substring, so this grep matched both lines:
PMONGODB_URL=mongodb://admin:<password>@… ← matched (unwanted)
MONGODB_URL=mongodb://admin:<password>@… ← matched (wanted)
The captured shell variable ended up holding two concatenated values with an embedded newline. When
it was later diffed for key-name verification (cut -d= -f1), the bare unprefixed fragment surfaced
as a visible line — printing a full mongodb://admin:<password>@… URI into the transcript.
This is a prefix-collision: whenever one env key is a suffix of another
(MONGODB_URL ⊂ PMONGODB_URL, DB_URL ⊂ APP_DB_URL, KEY ⊂ API_KEY), an unanchored match
leaks the sibling key’s value.
The rule
Always anchor at line-start with ^KEY= and require exactly one match. The ^ anchor alone
already defeats the prefix-collision (^MONGODB_URL= cannot match PMONGODB_URL=); requiring a
single match additionally catches accidental duplicate keys.
# ✅ CORRECT — anchored, exact key, value captured silently, never echoed
VALUE=$(grep "^MONGODB_URL=" backend-environment.env | cut -d= -f2-)
some-command --uri "$VALUE"; unset VALUENever cat / Read a credential file, never print the captured variable, and reference the KEY
NAME only in any diagnostic output — per the global secret-safety rules in CLAUDE.md.
Preferred: use the shared helper
scripts/lib/extract_env_key.sh encapsulates all four guarantees (anchored ^KEY=, exactly-one-match
enforcement, value to stdout only, regex-injection-proof key validation). Prefer it over hand-written
greps in scripts and rotation tooling:
source /opt/p24-infra/scripts/lib/extract_env_key.sh
# From a file:
VALUE=$(extract_env_key MONGODB_URL backend-environment.env) || { echo "extract failed" >&2; exit 1; }
some-command --uri "$VALUE"; unset VALUE
# From a SOPS-decrypted stream (keeps plaintext off disk):
VALUE=$(sops -d --input-type dotenv --output-type dotenv secrets/pinbox24-w3.env.sops \
| extract_env_key_stdin V32_MONGODB_URL) || exit 1Exit codes: 0 one match (value on stdout) · 1 bad usage / invalid key / unreadable file ·
2 key absent · 3 duplicate/collision (value withheld). Under set -e any non-zero aborts the
caller, so a collision can never silently pass through.
Self-test (synthetic non-secret fixtures, reproduces the exact #3494 collision):
bash scripts/lib/extract_env_key.sh --self-testChecklist before extracting any value from a dotenv/SOPS file
- Grep is anchored:
^KEY=(or useextract_env_key) — never a bareKEY=. - Exactly one match is required; the command fails on zero or many.
- The value is captured into a variable and used as a command argument — never printed.
- No later
diff/cut/ verification step echoes lines that contain the value. - Diagnostics reference the KEY NAME only.
- Temp plaintext files are deleted and value variables
unsetimmediately after use.
Related: docs/secrets-rotation-log.md (#3494 entry), docs/playbooks/sops-edit-operations.md,
docs/playbooks/static-api-key-incident-rotation.md, CLAUDE.md §Secrets.