main
md 200 lines 7.37 KB
Rendered Raw
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