@baselane/packs 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aliases.js +1 -0
- package/package.json +2 -2
- package/packs/database-review/pack.json +75 -9
- package/packs/database-review/rendered/.claude/agents/database-reviewer.md +75 -2
- package/packs/database-review/rendered/.claude/commands/migration-review.md +6 -0
- package/packs/database-review/rendered/.claude/settings.json +11 -0
- package/packs/database-review/rendered/.claude/skills/database-migrations/SKILL.md +431 -0
- package/packs/database-review/rendered/.claude/skills/mysql-patterns/SKILL.md +414 -0
- package/packs/database-review/rendered/.claude/skills/postgres-patterns/SKILL.md +149 -0
- package/packs/database-review/rendered/.github/copilot-instructions.md +1096 -14
- package/packs/database-review/rendered/AGENTS.md +45 -16
- package/packs/database-review/rendered/CLAUDE.md +4 -0
- package/packs/database-review/rendered/GEMINI.md +987 -0
- package/packs/go-rules/pack.json +65 -9
- package/packs/go-rules/rendered/.claude/agents/go-build-resolver.md +90 -0
- package/packs/go-rules/rendered/.claude/agents/go-reviewer.md +72 -2
- package/packs/go-rules/rendered/.claude/commands/go-build.md +6 -0
- package/packs/go-rules/rendered/.claude/commands/go-review.md +1 -1
- package/packs/go-rules/rendered/.claude/commands/go-test.md +6 -0
- package/packs/go-rules/rendered/.claude/settings.json +9 -0
- package/packs/go-rules/rendered/.claude/skills/golang-patterns/SKILL.md +673 -0
- package/packs/go-rules/rendered/.claude/skills/golang-testing/SKILL.md +719 -0
- package/packs/go-rules/rendered/.github/copilot-instructions.md +1783 -7
- package/packs/go-rules/rendered/AGENTS.md +244 -8
- package/packs/go-rules/rendered/CLAUDE.md +5 -0
- package/packs/go-rules/rendered/GEMINI.md +1394 -0
- package/packs/python-rules/pack.json +87 -10
- package/packs/python-rules/rendered/.claude/agents/django-reviewer.md +159 -0
- package/packs/python-rules/rendered/.claude/agents/fastapi-reviewer.md +70 -0
- package/packs/python-rules/rendered/.claude/agents/python-reviewer.md +92 -2
- package/packs/python-rules/rendered/.claude/commands/django-review.md +6 -0
- package/packs/python-rules/rendered/.claude/commands/fastapi-review.md +6 -0
- package/packs/python-rules/rendered/.claude/commands/python-review.md +1 -1
- package/packs/python-rules/rendered/.claude/settings.json +1 -1
- package/packs/python-rules/rendered/.claude/skills/django-security/SKILL.md +642 -0
- package/packs/python-rules/rendered/.claude/skills/django-tdd/SKILL.md +728 -0
- package/packs/python-rules/rendered/.claude/skills/fastapi-patterns/SKILL.md +512 -0
- package/packs/python-rules/rendered/.claude/skills/python-patterns/SKILL.md +749 -0
- package/packs/python-rules/rendered/.claude/skills/python-testing/SKILL.md +815 -0
- package/packs/python-rules/rendered/.github/copilot-instructions.md +3815 -12
- package/packs/python-rules/rendered/AGENTS.md +73 -13
- package/packs/python-rules/rendered/CLAUDE.md +9 -0
- package/packs/python-rules/rendered/GEMINI.md +3448 -0
- package/packs/security-review/pack.json +51 -7
- package/packs/security-review/rendered/.claude/agents/security-reviewer.md +29 -2
- package/packs/security-review/rendered/.claude/settings.json +11 -0
- package/packs/security-review/rendered/.claude/skills/security-review/SKILL.md +302 -0
- package/packs/security-review/rendered/.claude/skills/security-review/cloud-infrastructure-security.md +171 -0
- package/packs/security-review/rendered/.claude/skills/security-scan-config/SKILL.md +56 -0
- package/packs/security-review/rendered/.github/copilot-instructions.md +658 -15
- package/packs/security-review/rendered/AGENTS.md +283 -17
- package/packs/security-review/rendered/CLAUDE.md +2 -0
- package/packs/security-review/rendered/GEMINI.md +352 -0
- package/packs/software-engineer-harness/pack.json +249 -13
- package/packs/software-engineer-harness/rendered/.claude/agents/code-explorer.md +67 -0
- package/packs/software-engineer-harness/rendered/.claude/agents/performance-optimizer.md +444 -0
- package/packs/software-engineer-harness/rendered/.claude/agents/pr-test-analyzer.md +43 -0
- package/packs/software-engineer-harness/rendered/.claude/commands/feature-dev.md +6 -0
- package/packs/software-engineer-harness/rendered/.claude/settings.json +29 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/api-design/SKILL.md +522 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/architecture-decision-records/SKILL.md +178 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/backend-patterns/SKILL.md +560 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/codebase-onboarding/SKILL.md +232 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/deployment-patterns/SKILL.md +426 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/docker-patterns/SKILL.md +363 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/e2e-testing/SKILL.md +325 -0
- package/packs/software-engineer-harness/rendered/.claude/skills/tdd-workflow/SKILL.md +580 -0
- package/packs/software-engineer-harness/rendered/.github/copilot-instructions.md +3948 -2
- package/packs/software-engineer-harness/rendered/AGENTS.md +194 -4
- package/packs/software-engineer-harness/rendered/CLAUDE.md +20 -0
- package/packs/software-engineer-harness/rendered/GEMINI.md +3208 -0
- package/packs/typescript-rules/pack.json +68 -5
- package/packs/typescript-rules/rendered/.claude/agents/react-reviewer.md +165 -0
- package/packs/typescript-rules/rendered/.claude/agents/type-design-analyzer.md +48 -0
- package/packs/typescript-rules/rendered/.claude/commands/react-review.md +6 -0
- package/packs/typescript-rules/rendered/.claude/settings.json +9 -0
- package/packs/typescript-rules/rendered/.claude/skills/react-patterns/SKILL.md +340 -0
- package/packs/typescript-rules/rendered/.claude/skills/react-performance/SKILL.md +573 -0
- package/packs/typescript-rules/rendered/.claude/skills/react-testing/SKILL.md +422 -0
- package/packs/typescript-rules/rendered/.github/copilot-instructions.md +2459 -53
- package/packs/typescript-rules/rendered/AGENTS.md +893 -17
- package/packs/typescript-rules/rendered/CLAUDE.md +6 -0
- package/packs/typescript-rules/rendered/GEMINI.md +1335 -0
- package/packs/ecc-essentials/pack.json +0 -93
- package/packs/ecc-essentials/rendered/.claude/settings.json +0 -37
- package/packs/ecc-essentials/rendered/.github/copilot-instructions.md +0 -110
- package/packs/ecc-essentials/rendered/AGENTS.md +0 -74
- package/packs/ecc-essentials/rendered/CLAUDE.md +0 -14
- package/packs/ecc-essentials/rendered/GEMINI.md +0 -25
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/build-error-resolver.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/refactor-cleaner.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/silent-failure-hunter.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/tdd-guide.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/fix-build.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/hunt-silent-failures.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/tdd.md +0 -0
- /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/skills/tdd-red-green-refactor/SKILL.md +0 -0
|
@@ -88,3 +88,355 @@ the failure where the bad data actually entered, where the error message can sti
|
|
|
88
88
|
HTTP request bodies and query params · file and config contents · third-party API responses ·
|
|
89
89
|
environment variables (validate presence and format at startup) · deserialized messages/events ·
|
|
90
90
|
anything read from a store you did not just write in the same transaction.
|
|
91
|
+
|
|
92
|
+
### security-review
|
|
93
|
+
|
|
94
|
+
Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Full worked checklist with code examples for every OWASP Top 10 category, plus a cloud-infrastructure reference.
|
|
95
|
+
|
|
96
|
+
# Security review
|
|
97
|
+
|
|
98
|
+
Comprehensive security review discipline for code that adds authentication, handles user input, works with secrets, exposes an API endpoint, or touches payment/sensitive data. This is the full checklist version of the pack's own context — use it when you need the worked examples inline rather than the summary.
|
|
99
|
+
|
|
100
|
+
## When to activate
|
|
101
|
+
|
|
102
|
+
- Implementing authentication or authorization
|
|
103
|
+
- Handling user input or file uploads
|
|
104
|
+
- Creating new API endpoints
|
|
105
|
+
- Working with secrets or credentials
|
|
106
|
+
- Implementing payment features
|
|
107
|
+
- Storing or transmitting sensitive data
|
|
108
|
+
- Integrating third-party APIs
|
|
109
|
+
|
|
110
|
+
## Secrets management
|
|
111
|
+
|
|
112
|
+
FAIL:
|
|
113
|
+
```typescript
|
|
114
|
+
const apiKey = "sk-proj-xxxxx" // hardcoded secret
|
|
115
|
+
const dbPassword = "password123" // in source code
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
PASS:
|
|
119
|
+
```typescript
|
|
120
|
+
const apiKey = process.env.OPENAI_API_KEY
|
|
121
|
+
if (!apiKey) throw new Error('OPENAI_API_KEY not configured')
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Verify: no hardcoded API keys/tokens/passwords · all secrets in env vars · `.env.local` gitignored · no secrets in git history · production secrets in the hosting platform's secret store.
|
|
125
|
+
|
|
126
|
+
## Input validation
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { z } from 'zod'
|
|
130
|
+
|
|
131
|
+
const CreateUserSchema = z.object({
|
|
132
|
+
email: z.string().email(),
|
|
133
|
+
name: z.string().min(1).max(100),
|
|
134
|
+
age: z.number().int().min(0).max(150)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
export async function createUser(input: unknown) {
|
|
138
|
+
try {
|
|
139
|
+
const validated = CreateUserSchema.parse(input)
|
|
140
|
+
return await db.users.create(validated)
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof z.ZodError) return { success: false, errors: error.issues }
|
|
143
|
+
throw error
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
File upload validation checks size, MIME type, AND extension — never just one:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
function validateFileUpload(file: File) {
|
|
152
|
+
const maxSize = 5 * 1024 * 1024
|
|
153
|
+
if (file.size > maxSize) throw new Error('File too large (max 5MB)')
|
|
154
|
+
|
|
155
|
+
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
|
|
156
|
+
if (!allowedTypes.includes(file.type)) throw new Error('Invalid file type')
|
|
157
|
+
|
|
158
|
+
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
|
|
159
|
+
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
|
|
160
|
+
if (!extension || !allowedExtensions.includes(extension)) throw new Error('Invalid file extension')
|
|
161
|
+
|
|
162
|
+
return true
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Verify: all user inputs validated with schemas · file uploads restricted (size, type, extension) · no direct use of user input in queries · whitelist validation (not blacklist) · error messages don't leak sensitive info.
|
|
167
|
+
|
|
168
|
+
## SQL injection prevention
|
|
169
|
+
|
|
170
|
+
FAIL:
|
|
171
|
+
```typescript
|
|
172
|
+
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
|
|
173
|
+
await db.query(query)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
PASS:
|
|
177
|
+
```typescript
|
|
178
|
+
const { data } = await supabase.from('users').select('*').eq('email', userEmail)
|
|
179
|
+
// or
|
|
180
|
+
await db.query('SELECT * FROM users WHERE email = $1', [userEmail])
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Verify: all database queries use parameterized queries · no string concatenation in SQL · ORM/query builder used correctly.
|
|
184
|
+
|
|
185
|
+
## Authentication & authorization
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// FAIL: localStorage is vulnerable to XSS
|
|
189
|
+
localStorage.setItem('token', token)
|
|
190
|
+
|
|
191
|
+
// PASS: httpOnly cookie
|
|
192
|
+
res.setHeader('Set-Cookie', `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
export async function deleteUser(userId: string, requesterId: string) {
|
|
197
|
+
const requester = await db.users.findUnique({ where: { id: requesterId } })
|
|
198
|
+
if (requester.role !== 'admin') {
|
|
199
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 403 })
|
|
200
|
+
}
|
|
201
|
+
await db.users.delete({ where: { id: userId } })
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Row-level security (e.g. Supabase):
|
|
206
|
+
|
|
207
|
+
```sql
|
|
208
|
+
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
|
209
|
+
|
|
210
|
+
CREATE POLICY "Users view own data" ON users FOR SELECT USING (auth.uid() = id);
|
|
211
|
+
CREATE POLICY "Users update own data" ON users FOR UPDATE USING (auth.uid() = id);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Verify: tokens in httpOnly cookies (not localStorage) · authorization checks before sensitive operations · row-level security enabled where supported · role-based access control implemented · session management secure.
|
|
215
|
+
|
|
216
|
+
## XSS prevention
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import DOMPurify from 'isomorphic-dompurify'
|
|
220
|
+
|
|
221
|
+
function renderUserContent(html: string) {
|
|
222
|
+
const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'], ALLOWED_ATTR: [] })
|
|
223
|
+
return <div dangerouslySetInnerHTML={{ __html: clean }} />
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Content-Security-Policy — start strict and loosen only with a documented removal plan; don't default to `'unsafe-inline'` or `'unsafe-eval'`:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const securityHeaders = [{
|
|
231
|
+
key: 'Content-Security-Policy',
|
|
232
|
+
value: `
|
|
233
|
+
default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none';
|
|
234
|
+
script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self';
|
|
235
|
+
connect-src 'self' https://api.example.com;
|
|
236
|
+
`.replace(/\s{2,}/g, ' ').trim()
|
|
237
|
+
}]
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Verify: user-provided HTML sanitized · CSP headers configured · no unvalidated dynamic content rendering · framework's built-in XSS protection used, not bypassed.
|
|
241
|
+
|
|
242
|
+
## CSRF protection
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
export async function POST(request: Request) {
|
|
246
|
+
const token = request.headers.get('X-CSRF-Token')
|
|
247
|
+
if (!csrf.verify(token)) return NextResponse.json({ error: 'Invalid CSRF token' }, { status: 403 })
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
res.setHeader('Set-Cookie', `session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Verify: CSRF tokens on state-changing operations · `SameSite=Strict` on all cookies · double-submit cookie pattern where applicable.
|
|
256
|
+
|
|
257
|
+
## Rate limiting
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import rateLimit from 'express-rate-limit'
|
|
261
|
+
|
|
262
|
+
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100, message: 'Too many requests' })
|
|
263
|
+
app.use('/api/', limiter)
|
|
264
|
+
|
|
265
|
+
const searchLimiter = rateLimit({ windowMs: 60 * 1000, max: 10, message: 'Too many search requests' })
|
|
266
|
+
app.use('/api/search', searchLimiter)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Verify: rate limiting on all API endpoints · stricter limits on expensive operations · IP-based and, where authenticated, user-based limits.
|
|
270
|
+
|
|
271
|
+
## Sensitive data exposure
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
// FAIL
|
|
275
|
+
console.log('User login:', { email, password })
|
|
276
|
+
console.log('Payment:', { cardNumber, cvv })
|
|
277
|
+
|
|
278
|
+
// PASS
|
|
279
|
+
console.log('User login:', { email, userId })
|
|
280
|
+
console.log('Payment:', { last4: card.last4, userId })
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
// FAIL
|
|
285
|
+
catch (error) {
|
|
286
|
+
return NextResponse.json({ error: error.message, stack: error.stack }, { status: 500 })
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// PASS
|
|
290
|
+
catch (error) {
|
|
291
|
+
console.error('Internal error:', error)
|
|
292
|
+
return NextResponse.json({ error: 'An error occurred. Please try again.' }, { status: 500 })
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Verify: no passwords/tokens/secrets in logs · error messages generic for users · detailed errors server-side only · no stack traces exposed to users.
|
|
297
|
+
|
|
298
|
+
## Signed-transaction verification (any system that signs/authorizes value transfer)
|
|
299
|
+
|
|
300
|
+
Wherever a system accepts a signed message or transaction authorizing a transfer of value (payments, on-chain transactions, signed API mutations), verify the signature AND re-check business constraints server-side — never trust a client-reported amount or recipient:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
async function verifyTransaction(transaction: Transaction) {
|
|
304
|
+
if (transaction.to !== expectedRecipient) throw new Error('Invalid recipient')
|
|
305
|
+
if (transaction.amount > maxAmount) throw new Error('Amount exceeds limit')
|
|
306
|
+
const balance = await getBalance(transaction.from)
|
|
307
|
+
if (balance < transaction.amount) throw new Error('Insufficient balance')
|
|
308
|
+
return true
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Verify: signatures verified · transaction/mutation details re-validated server-side · balance/limit checks before committing · no blind signing of client-supplied payloads.
|
|
313
|
+
|
|
314
|
+
## Dependency security
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm audit
|
|
318
|
+
npm audit fix
|
|
319
|
+
npm update
|
|
320
|
+
npm outdated
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
git add package-lock.json # always commit lock files
|
|
325
|
+
npm ci # in CI, for reproducible builds
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Verify: dependencies up to date · no known vulnerabilities (`npm audit` clean) · lock files committed · automated dependency update tooling enabled · regular security updates.
|
|
329
|
+
|
|
330
|
+
## Security testing
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
test('requires authentication', async () => {
|
|
334
|
+
const response = await fetch('/api/protected')
|
|
335
|
+
expect(response.status).toBe(401)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
test('requires admin role', async () => {
|
|
339
|
+
const response = await fetch('/api/admin', { headers: { Authorization: `Bearer ${userToken}` } })
|
|
340
|
+
expect(response.status).toBe(403)
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
test('rejects invalid input', async () => {
|
|
344
|
+
const response = await fetch('/api/users', { method: 'POST', body: JSON.stringify({ email: 'not-an-email' }) })
|
|
345
|
+
expect(response.status).toBe(400)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
test('enforces rate limits', async () => {
|
|
349
|
+
const requests = Array(101).fill(null).map(() => fetch('/api/endpoint'))
|
|
350
|
+
const responses = await Promise.all(requests)
|
|
351
|
+
expect(responses.filter(r => r.status === 429).length).toBeGreaterThan(0)
|
|
352
|
+
})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Pre-deployment security checklist
|
|
356
|
+
|
|
357
|
+
Before ANY production deployment:
|
|
358
|
+
|
|
359
|
+
- [ ] Secrets: no hardcoded secrets, all in env vars
|
|
360
|
+
- [ ] Input validation: all user inputs validated
|
|
361
|
+
- [ ] SQL injection: all queries parameterized
|
|
362
|
+
- [ ] XSS: user content sanitized
|
|
363
|
+
- [ ] CSRF: protection enabled
|
|
364
|
+
- [ ] Authentication: proper token handling
|
|
365
|
+
- [ ] Authorization: role checks in place
|
|
366
|
+
- [ ] Rate limiting: enabled on all endpoints
|
|
367
|
+
- [ ] HTTPS: enforced in production
|
|
368
|
+
- [ ] Security headers: CSP, X-Frame-Options configured
|
|
369
|
+
- [ ] Error handling: no sensitive data in errors
|
|
370
|
+
- [ ] Logging: no sensitive data logged
|
|
371
|
+
- [ ] Dependencies: up to date, no vulnerabilities
|
|
372
|
+
- [ ] Row-level security: enabled where supported
|
|
373
|
+
- [ ] CORS: properly configured
|
|
374
|
+
- [ ] File uploads: validated (size, type)
|
|
375
|
+
- [ ] Signed transactions: signatures and business constraints re-verified server-side (if applicable)
|
|
376
|
+
|
|
377
|
+
## Common false positives
|
|
378
|
+
|
|
379
|
+
- Environment variables in `.env.example` (not actual secrets)
|
|
380
|
+
- Test credentials in test files, clearly marked as such
|
|
381
|
+
- Public API keys that are actually meant to be public
|
|
382
|
+
- SHA-256/MD5 used for checksums, not password storage
|
|
383
|
+
|
|
384
|
+
Always verify context before flagging.
|
|
385
|
+
|
|
386
|
+
## Resources
|
|
387
|
+
|
|
388
|
+
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
389
|
+
- [Web Security Academy](https://portswigger.net/web-security)
|
|
390
|
+
|
|
391
|
+
### security-scan-config
|
|
392
|
+
|
|
393
|
+
Scan this project's AI-harness configuration (settings, CLAUDE.md/AGENTS.md, MCP servers, hooks, agent definitions) for secrets, dangerous permission bypasses, and prompt-injection risk — before committing configuration changes.
|
|
394
|
+
|
|
395
|
+
# Security scan (harness configuration)
|
|
396
|
+
|
|
397
|
+
Scan this project's AI-harness configuration (`.claude/` or equivalent) for security misconfigurations and prompt-injection risk — a separate concern from application code, but part of the same trust boundary in an AI-assisted repo.
|
|
398
|
+
|
|
399
|
+
## When to activate
|
|
400
|
+
|
|
401
|
+
- Setting up a new AI-harness project configuration
|
|
402
|
+
- After modifying `settings.json`, `CLAUDE.md`/`AGENTS.md`, or MCP server configs
|
|
403
|
+
- Before committing configuration changes
|
|
404
|
+
- When onboarding to a repo with an existing harness configuration
|
|
405
|
+
- Periodic security hygiene checks
|
|
406
|
+
|
|
407
|
+
## What to review
|
|
408
|
+
|
|
409
|
+
| File | Checks |
|
|
410
|
+
| --- | --- |
|
|
411
|
+
| `CLAUDE.md` / `AGENTS.md` | Hardcoded secrets, auto-run instructions embedded in project docs, prompt-injection patterns |
|
|
412
|
+
| `settings.json` | Overly permissive allow lists, missing deny lists, dangerous bypass flags (e.g. skip-permissions) |
|
|
413
|
+
| MCP server config | Risky/unaudited servers, hardcoded secrets in server env, unpinned `npx`-style install-on-run entries |
|
|
414
|
+
| hooks | Command injection via unescaped interpolation into a shell command, silent error suppression (`2>/dev/null`, `\|\| true`), unexplained outbound network calls |
|
|
415
|
+
| agent definitions | Unrestricted tool access (e.g. unconditional Bash) where the task doesn't need it, missing model spec, prompt-injection surface from untrusted inputs |
|
|
416
|
+
|
|
417
|
+
## Manual scan (portable, no extra tooling)
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
# hardcoded-looking secrets in harness config
|
|
421
|
+
grep -rEn '(api[_-]?key|secret|token|password)\s*[:=]\s*["\x27][A-Za-z0-9/+=_-]{12,}' .claude/ CLAUDE.md AGENTS.md 2>/dev/null
|
|
422
|
+
|
|
423
|
+
# unrestricted shell / dangerous bypass flags
|
|
424
|
+
grep -rn 'Bash(\*)\|dangerously-skip-permissions\|--no-verify' .claude/settings*.json 2>/dev/null
|
|
425
|
+
|
|
426
|
+
# hook commands that interpolate a file path or tool output directly into a shell string
|
|
427
|
+
grep -rn '${.*}|$(.*)' .claude/settings*.json 2>/dev/null | grep -i hook
|
|
428
|
+
|
|
429
|
+
# silent error suppression in hooks (hides a failing check rather than fixing it)
|
|
430
|
+
grep -rn '2>/dev/null\|\|\| true' .claude/settings*.json 2>/dev/null
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Severity levels
|
|
434
|
+
|
|
435
|
+
- **CRITICAL** — hardcoded API keys/tokens in config; `Bash(*)` (or equivalent unrestricted shell) in the allow list; command injection in a hook via unescaped interpolation; a shell-executing MCP server with no scoping.
|
|
436
|
+
- **HIGH** — auto-run instructions embedded in project docs (a prompt-injection vector any collaborator's harness will read); missing deny lists on sensitive paths (`~/.ssh`, `~/.aws`, `.env*`); an agent with Bash access it doesn't need for its stated task.
|
|
437
|
+
- **MEDIUM** — silent error suppression in hooks; missing a pre-tool-use security hook on Bash; unpinned install-on-run entries in MCP server config.
|
|
438
|
+
- **INFO** — missing descriptions on MCP servers or agents; explicit prohibitive instructions correctly present (flag as good practice, not a finding).
|
|
439
|
+
|
|
440
|
+
## Resources
|
|
441
|
+
|
|
442
|
+
- [OWASP MCP Top 10](https://owasp.org/) — tool poisoning, prompt injection via contextual payloads, command injection, shadow MCP servers, secret exposure.
|