SKILL.md (7747B)
1 --- 2 name: secret-handling 3 description: Never read .env files or write secrets to .squad/ committed files 4 domain: security, file-operations, team-collaboration 5 confidence: high 6 source: earned (issue #267 — credential leak incident) 7 --- 8 9 ## Context 10 11 Spawned agents have read access to the entire repository, including `.env` files containing live credentials. If an agent reads secrets and writes them to `.squad/` files (decisions, logs, history), Scribe auto-commits them to git, exposing them in remote history. This skill codifies absolute prohibitions and safe alternatives. 12 13 ## Patterns 14 15 ### Prohibited File Reads 16 17 **NEVER read these files:** 18 - `.env` (production secrets) 19 - `.env.local` (local dev secrets) 20 - `.env.production` (production environment) 21 - `.env.development` (development environment) 22 - `.env.staging` (staging environment) 23 - `.env.test` (test environment with real credentials) 24 - Any file matching `.env.*` UNLESS explicitly allowed (see below) 25 26 **Allowed alternatives:** 27 - `.env.example` (safe — contains placeholder values, no real secrets) 28 - `.env.sample` (safe — documentation template) 29 - `.env.template` (safe — schema/structure reference) 30 31 **If you need config info:** 32 1. **Ask the user directly** — "What's the database connection string?" 33 2. **Read `.env.example`** — shows structure without exposing secrets 34 3. **Read documentation** — check `README.md`, `docs/`, config guides 35 36 **NEVER assume you can "just peek at .env to understand the schema."** Use `.env.example` or ask. 37 38 ### Prohibited Output Patterns 39 40 **NEVER write these to `.squad/` files:** 41 42 | Pattern Type | Examples | Regex Pattern (for scanning) | 43 |--------------|----------|-------------------------------| 44 | API Keys | `OPENAI_API_KEY=sk-proj-...`, `GITHUB_TOKEN=ghp_...` | `[A-Z_]+(?:KEY|TOKEN|SECRET)=[^\s]+` | 45 | Passwords | `DB_PASSWORD=super_secret_123`, `password: "..."` | `(?:PASSWORD|PASS|PWD)[:=]\s*["']?[^\s"']+` | 46 | Connection Strings | `postgres://user:pass@host:5432/db`, `Server=...;Password=...` | `(?:postgres|mysql|mongodb)://[^@]+@|(?:Server|Host)=.*(?:Password|Pwd)=` | 47 | JWT Tokens | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` | `eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+` | 48 | Private Keys | `-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` | `-----BEGIN [A-Z ]+PRIVATE KEY-----` | 49 | AWS Credentials | `AKIA...`, `aws_secret_access_key=...` | `AKIA[0-9A-Z]{16}|aws_secret_access_key=[^\s]+` | 50 | Email Addresses | `user@example.com` (PII violation per team decision) | `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}` | 51 52 **What to write instead:** 53 - Placeholder values: `DATABASE_URL=<set in .env>` 54 - Redacted references: `API key configured (see .env.example)` 55 - Architecture notes: "App uses JWT auth — token stored in session" 56 - Schema documentation: "Requires OPENAI_API_KEY, GITHUB_TOKEN (see .env.example for format)" 57 58 ### Scribe Pre-Commit Validation 59 60 **Before committing `.squad/` changes, Scribe MUST:** 61 62 1. **Scan all staged files** for secret patterns (use regex table above) 63 2. **Check for prohibited file names** (don't commit `.env` even if manually staged) 64 3. **If secrets detected:** 65 - STOP the commit (do NOT proceed) 66 - Remove the file from staging: `git reset HEAD <file>` 67 - Report to user: 68 ``` 69 🚨 SECRET DETECTED — commit blocked 70 71 File: .squad/decisions/inbox/river-db-config.md 72 Pattern: DATABASE_URL=postgres://user:password@localhost:5432/prod 73 74 This file contains credentials and MUST NOT be committed. 75 Please remove the secret, replace with placeholder, and try again. 76 ``` 77 - Exit with error (never silently skip) 78 79 4. **If no secrets detected:** 80 - Proceed with commit as normal 81 82 **Implementation note for Scribe:** 83 - Run validation AFTER staging files, BEFORE calling `git commit` 84 - Use PowerShell `Select-String` or `git diff --cached` to scan staged content 85 - Fail loud — secret leaks are unacceptable, blocking the commit is correct behavior 86 87 ### Remediation — If a Secret Was Already Committed 88 89 **If you discover a secret in git history:** 90 91 1. **STOP immediately** — do not make more commits 92 2. **Alert the user:** 93 ``` 94 🚨 CREDENTIAL LEAK DETECTED 95 96 A secret was found in git history: 97 Commit: abc1234 98 File: .squad/decisions/inbox/agent-config.md 99 Pattern: API_KEY=sk-proj-... 100 101 This requires immediate remediation: 102 1. Revoke the exposed credential (regenerate API key, rotate password) 103 2. Remove from git history (git filter-repo or BFG) 104 3. Force-push the cleaned history 105 106 Do NOT proceed with new work until this is resolved. 107 ``` 108 3. **Do NOT attempt to fix it yourself** — secret removal requires specialized tools 109 4. **Wait for user confirmation** before resuming work 110 111 ## Examples 112 113 ### ✓ Correct: Reading Config Schema 114 115 **Agent needs to know what environment variables are required:** 116 117 ``` 118 Agent: "What environment variables does this app need?" 119 → Reads `.env.example`: 120 OPENAI_API_KEY=sk-... 121 DATABASE_URL=postgres://user:pass@localhost:5432/db 122 REDIS_URL=redis://localhost:6379 123 124 → Writes to .squad/decisions/inbox/river-env-setup.md: 125 "App requires three environment variables: 126 - OPENAI_API_KEY (OpenAI API key, format: sk-...) 127 - DATABASE_URL (Postgres connection string) 128 - REDIS_URL (Redis connection string) 129 See .env.example for full schema." 130 ``` 131 132 ### ✗ Incorrect: Reading Live Credentials 133 134 **Agent needs to know database schema:** 135 136 ``` 137 Agent: (reads .env) 138 DATABASE_URL=postgres://admin:super_secret_pw@prod.example.com:5432/appdb 139 140 → Writes to .squad/decisions/inbox/river-db-schema.md: 141 "Database connection: postgres://admin:super_secret_pw@prod.example.com:5432/appdb" 142 143 🚨 VIOLATION: Live credential written to committed file 144 ``` 145 146 **Correct approach:** 147 ``` 148 Agent: (reads .env.example OR asks user) 149 User: "It's a Postgres database, schema is in migrations/" 150 151 → Writes to .squad/decisions/inbox/river-db-schema.md: 152 "Database: Postgres (connection configured in .env). Schema defined in db/migrations/." 153 ``` 154 155 ### ✓ Correct: Scribe Pre-Commit Validation 156 157 **Scribe is about to commit:** 158 159 ```powershell 160 # Stage files 161 git add .squad/ 162 163 # Scan staged content for secrets 164 $stagedContent = git diff --cached 165 $secretPatterns = @( 166 '[A-Z_]+(?:KEY|TOKEN|SECRET)=[^\s]+', 167 '(?:PASSWORD|PASS|PWD)[:=]\s*["'']?[^\s"'']+', 168 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' 169 ) 170 171 $detected = $false 172 foreach ($pattern in $secretPatterns) { 173 if ($stagedContent -match $pattern) { 174 $detected = $true 175 Write-Host "🚨 SECRET DETECTED: $($matches[0])" 176 break 177 } 178 } 179 180 if ($detected) { 181 # Remove from staging, report, exit 182 git reset HEAD .squad/ 183 Write-Error "Commit blocked — secret detected in staged files" 184 exit 1 185 } 186 187 # Safe to commit 188 git commit -F $msgFile 189 ``` 190 191 ## Anti-Patterns 192 193 - ❌ Reading `.env` "just to check the schema" — use `.env.example` instead 194 - ❌ Writing "sanitized" connection strings that still contain credentials 195 - ❌ Assuming "it's just a dev environment" makes secrets safe to commit 196 - ❌ Committing first, scanning later — validation MUST happen before commit 197 - ❌ Silently skipping secret detection — fail loud, never silent 198 - ❌ Trusting agents to "know better" — enforce at multiple layers (prompt, hook, architecture) 199 - ❌ Writing secrets to "temporary" files in `.squad/` — Scribe commits ALL `.squad/` changes 200 - ❌ Extracting "just the host" from a connection string — still leaks infrastructure topology