fix(#429): prevent API keys from being committed via map-codebase
Defense-in-depth approach: Layer 1 - Prevention: - Add <forbidden_files> 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 <noreply@anthropic.com>
This commit is contained in:
31
README.md
31
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?**
|
||||
|
||||
@@ -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.
|
||||
|
||||
</templates>
|
||||
|
||||
<forbidden_files>
|
||||
**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.
|
||||
</forbidden_files>
|
||||
|
||||
<critical_rules>
|
||||
|
||||
**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 <forbidden_files>.**
|
||||
|
||||
**RETURN ONLY CONFIRMATION.** Your response should be ~10 lines max. Just confirm what was written.
|
||||
|
||||
|
||||
@@ -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.
|
||||
</step>
|
||||
|
||||
<step name="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.
|
||||
</step>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user