From f53011c9e2d8f13cc580b04963d769d1a0304b51 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Thu, 5 Feb 2026 12:15:56 -0600 Subject: [PATCH] fix(#429): prevent API keys from being committed via map-codebase Defense-in-depth approach: Layer 1 - Prevention: - Add section to gsd-codebase-mapper agent - Explicitly prohibit reading .env, credentials, keys, secrets - Agent can note file existence but never quote contents Layer 2 - Detection: - Add scan_for_secrets step before commit in map-codebase workflow - Regex patterns catch: sk-*, ghp_*, AKIA*, xox*-*, JWTs, private keys - Halts with alert if secrets detected, requires user confirmation Layer 3 - Documentation: - Add Security section to README - Document Claude Code deny rules for sensitive files - Recommend defense-in-depth approach Closes #429 Co-Authored-By: Claude Opus 4.5 --- README.md | 31 ++++++++++++++++++++++ agents/gsd-codebase-mapper.md | 29 +++++++++++++++++--- get-shit-done/workflows/map-codebase.md | 35 +++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8566f08e0..52d8d1d7c 100644 --- a/README.md +++ b/README.md @@ -545,6 +545,37 @@ At milestone completion, GSD offers squash merge (recommended) or merge with his --- +## Security + +### Protecting Sensitive Files + +GSD's codebase mapping and analysis commands read files to understand your project. **Protect files containing secrets** by adding them to Claude Code's deny list: + +1. Open Claude Code settings (`.claude/settings.json` or global) +2. Add sensitive file patterns to the deny list: + +```json +{ + "permissions": { + "deny": [ + "Read(.env)", + "Read(.env.*)", + "Read(**/secrets/*)", + "Read(**/*credential*)", + "Read(**/*.pem)", + "Read(**/*.key)" + ] + } +} +``` + +This prevents Claude from reading these files entirely, regardless of what commands you run. + +> [!IMPORTANT] +> GSD includes built-in protections against committing secrets, but defense-in-depth is best practice. Deny read access to sensitive files as a first line of defense. + +--- + ## Troubleshooting **Commands not found after install?** diff --git a/agents/gsd-codebase-mapper.md b/agents/gsd-codebase-mapper.md index b351be592..c47ef2a19 100644 --- a/agents/gsd-codebase-mapper.md +++ b/agents/gsd-codebase-mapper.md @@ -85,8 +85,9 @@ Explore the codebase thoroughly for your focus area. ls package.json requirements.txt Cargo.toml go.mod pyproject.toml 2>/dev/null cat package.json 2>/dev/null | head -100 -# Config files -ls -la *.config.* .env* tsconfig.json .nvmrc .python-version 2>/dev/null +# Config files (list only - DO NOT read .env contents) +ls -la *.config.* tsconfig.json .nvmrc .python-version 2>/dev/null +ls .env* 2>/dev/null # Note existence only, never read contents # Find SDK/API imports grep -r "import.*stripe\|import.*supabase\|import.*aws\|import.*@" src/ --include="*.ts" --include="*.tsx" 2>/dev/null | head -50 @@ -712,6 +713,28 @@ Ready for orchestrator summary. + +**NEVER read or quote contents from these files (even if they exist):** + +- `.env`, `.env.*`, `*.env` - Environment variables with secrets +- `credentials.*`, `secrets.*`, `*secret*`, `*credential*` - Credential files +- `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.jks` - Certificates and private keys +- `id_rsa*`, `id_ed25519*`, `id_dsa*` - SSH private keys +- `.npmrc`, `.pypirc`, `.netrc` - Package manager auth tokens +- `config/secrets/*`, `.secrets/*`, `secrets/` - Secret directories +- `*.keystore`, `*.truststore` - Java keystores +- `serviceAccountKey.json`, `*-credentials.json` - Cloud service credentials +- `docker-compose*.yml` sections with passwords - May contain inline secrets +- Any file in `.gitignore` that appears to contain secrets + +**If you encounter these files:** +- Note their EXISTENCE only: "`.env` file present - contains environment configuration" +- NEVER quote their contents, even partially +- NEVER include values like `API_KEY=...` or `sk-...` in any output + +**Why this matters:** Your output gets committed to git. Leaked secrets = security incident. + + **WRITE DOCUMENTS DIRECTLY.** Do not return findings to orchestrator. The whole point is reducing context transfer. @@ -720,7 +743,7 @@ Ready for orchestrator summary. **USE THE TEMPLATES.** Fill in the template structure. Don't invent your own format. -**BE THOROUGH.** Explore deeply. Read actual files. Don't guess. +**BE THOROUGH.** Explore deeply. Read actual files. Don't guess. **But respect .** **RETURN ONLY CONFIRMATION.** Your response should be ~10 lines max. Just confirm what was written. diff --git a/get-shit-done/workflows/map-codebase.md b/get-shit-done/workflows/map-codebase.md index df59b5993..4de65de21 100644 --- a/get-shit-done/workflows/map-codebase.md +++ b/get-shit-done/workflows/map-codebase.md @@ -227,6 +227,41 @@ wc -l .planning/codebase/*.md If any documents missing or empty, note which agents may have failed. +Continue to scan_for_secrets. + + + +**CRITICAL SECURITY CHECK:** Scan output files for accidentally leaked secrets before committing. + +Run secret pattern detection: + +```bash +# Check for common API key patterns in generated docs +grep -E '(sk-[a-zA-Z0-9]{20,}|sk_live_[a-zA-Z0-9]+|sk_test_[a-zA-Z0-9]+|ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|glpat-[a-zA-Z0-9_-]+|AKIA[A-Z0-9]{16}|xox[baprs]-[a-zA-Z0-9-]+|-----BEGIN.*PRIVATE KEY|eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.)' .planning/codebase/*.md 2>/dev/null && SECRETS_FOUND=true || SECRETS_FOUND=false +``` + +**If SECRETS_FOUND=true:** + +``` +⚠️ SECURITY ALERT: Potential secrets detected in codebase documents! + +Found patterns that look like API keys or tokens in: +[show grep output] + +This would expose credentials if committed. + +**Action required:** +1. Review the flagged content above +2. If these are real secrets, they must be removed before committing +3. Consider adding sensitive files to Claude Code "Deny" permissions + +Pausing before commit. Reply "safe to proceed" if the flagged content is not actually sensitive, or edit the files first. +``` + +Wait for user confirmation before continuing to commit_codebase_map. + +**If SECRETS_FOUND=false:** + Continue to commit_codebase_map.