@bradtaylorsf/alpha-loop 1.0.0
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/LICENSE +21 -0
- package/README.md +294 -0
- package/agents/implementer.md +30 -0
- package/agents/reviewer.md +29 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +57 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.js +89 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/history.d.ts +8 -0
- package/dist/commands/history.js +185 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +241 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/run.d.ts +15 -0
- package/dist/commands/run.js +321 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +1 -0
- package/dist/commands/scan.js +50 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sync.d.ts +20 -0
- package/dist/commands/sync.js +149 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/vision.d.ts +1 -0
- package/dist/commands/vision.js +194 -0
- package/dist/commands/vision.js.map +1 -0
- package/dist/engine/agents.d.ts +41 -0
- package/dist/engine/agents.js +90 -0
- package/dist/engine/agents.js.map +1 -0
- package/dist/engine/config.d.ts +71 -0
- package/dist/engine/config.js +73 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/prerequisites.d.ts +34 -0
- package/dist/engine/prerequisites.js +90 -0
- package/dist/engine/prerequisites.js.map +1 -0
- package/dist/lib/agent.d.ts +25 -0
- package/dist/lib/agent.js +97 -0
- package/dist/lib/agent.js.map +1 -0
- package/dist/lib/config.d.ts +35 -0
- package/dist/lib/config.js +179 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/context.d.ts +17 -0
- package/dist/lib/context.js +96 -0
- package/dist/lib/context.js.map +1 -0
- package/dist/lib/github.d.ts +61 -0
- package/dist/lib/github.js +313 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/lib/learning.d.ts +43 -0
- package/dist/lib/learning.js +207 -0
- package/dist/lib/learning.js.map +1 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +28 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/pipeline.d.ts +18 -0
- package/dist/lib/pipeline.js +456 -0
- package/dist/lib/pipeline.js.map +1 -0
- package/dist/lib/preflight.d.ts +33 -0
- package/dist/lib/preflight.js +123 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/prerequisites.d.ts +12 -0
- package/dist/lib/prerequisites.js +54 -0
- package/dist/lib/prerequisites.js.map +1 -0
- package/dist/lib/prompts.d.ts +44 -0
- package/dist/lib/prompts.js +102 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/session.d.ts +28 -0
- package/dist/lib/session.js +173 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/shell.d.ts +32 -0
- package/dist/lib/shell.js +95 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/testing.d.ts +10 -0
- package/dist/lib/testing.js +51 -0
- package/dist/lib/testing.js.map +1 -0
- package/dist/lib/verify.d.ts +18 -0
- package/dist/lib/verify.js +235 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/vision.d.ts +9 -0
- package/dist/lib/vision.js +21 -0
- package/dist/lib/vision.js.map +1 -0
- package/dist/lib/worktree.d.ts +29 -0
- package/dist/lib/worktree.js +153 -0
- package/dist/lib/worktree.js.map +1 -0
- package/package.json +63 -0
- package/templates/agents/implementer.md +34 -0
- package/templates/agents/reviewer.md +48 -0
- package/templates/skills/code-review/SKILL.md +58 -0
- package/templates/skills/git-workflow/SKILL.md +53 -0
- package/templates/skills/implementation-planning/SKILL.md +64 -0
- package/templates/skills/security-analysis/SKILL.md +560 -0
- package/templates/skills/security-analysis/scripts/security-scanner.sh +227 -0
- package/templates/skills/test-robustness/SKILL.md +897 -0
- package/templates/skills/testing-patterns/SKILL.md +75 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-analysis
|
|
3
|
+
description: Comprehensive security vulnerability scanning and OWASP Top 10 compliance checking. Use when reviewing code for security issues, validating authentication/authorization, or ensuring security best practices.
|
|
4
|
+
auto_load: code-reviewer, backend-developer
|
|
5
|
+
priority: high
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Security Analysis Skill
|
|
9
|
+
|
|
10
|
+
## Quick Reference
|
|
11
|
+
|
|
12
|
+
Use this skill when:
|
|
13
|
+
- Reviewing code for security vulnerabilities
|
|
14
|
+
- Implementing authentication/authorization
|
|
15
|
+
- Validating input handling
|
|
16
|
+
- Checking for common security flaws
|
|
17
|
+
- Ensuring OWASP Top 10 compliance
|
|
18
|
+
|
|
19
|
+
## Metadata
|
|
20
|
+
|
|
21
|
+
**Category**: Security & Compliance
|
|
22
|
+
**Complexity**: Medium
|
|
23
|
+
**Time to Learn**: 30 minutes
|
|
24
|
+
**Prerequisites**: Understanding of web security basics
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Security Checklist (OWASP Top 10 2021)
|
|
29
|
+
|
|
30
|
+
### 1. Broken Access Control
|
|
31
|
+
|
|
32
|
+
**Check for**:
|
|
33
|
+
- Missing authorization checks on protected routes
|
|
34
|
+
- Insecure direct object references (IDOR)
|
|
35
|
+
- Privilege escalation vulnerabilities
|
|
36
|
+
|
|
37
|
+
**Example Vulnerable Code**:
|
|
38
|
+
```typescript
|
|
39
|
+
// ❌ BAD: No authorization check
|
|
40
|
+
router.delete('/api/users/:id', async (req, res) => {
|
|
41
|
+
await deleteUser(req.params.id);
|
|
42
|
+
res.status(204).send();
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Secure Alternative**:
|
|
47
|
+
```typescript
|
|
48
|
+
// ✅ GOOD: Verify user owns resource or is admin
|
|
49
|
+
router.delete('/api/users/:id', requireAuth, async (req, res) => {
|
|
50
|
+
const { id } = req.params;
|
|
51
|
+
const userId = req.user?.id;
|
|
52
|
+
|
|
53
|
+
// Check ownership or admin role
|
|
54
|
+
if (userId !== id && req.user?.role !== 'admin') {
|
|
55
|
+
throw new AppError('Forbidden', 403);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await deleteUser(id);
|
|
59
|
+
res.status(204).send();
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Automated Scan**:
|
|
64
|
+
```bash
|
|
65
|
+
# Find routes without auth middleware
|
|
66
|
+
grep -rn "router\.\(get\|post\|put\|delete\|patch\)" src/server/routes/ | \
|
|
67
|
+
grep -v "requireAuth\|isAuthenticated\|checkPermission" | \
|
|
68
|
+
grep -v "public" > potential-unauth-routes.txt
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### 2. Cryptographic Failures
|
|
74
|
+
|
|
75
|
+
**Check for**:
|
|
76
|
+
- Passwords stored in plain text
|
|
77
|
+
- Weak hashing algorithms (MD5, SHA1)
|
|
78
|
+
- Hardcoded secrets or API keys
|
|
79
|
+
- Insufficient bcrypt rounds (<10)
|
|
80
|
+
|
|
81
|
+
**Example Vulnerable Code**:
|
|
82
|
+
```typescript
|
|
83
|
+
// ❌ BAD: Weak hashing
|
|
84
|
+
import crypto from 'crypto';
|
|
85
|
+
const hash = crypto.createHash('md5').update(password).digest('hex');
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Secure Alternative**:
|
|
89
|
+
```typescript
|
|
90
|
+
// ✅ GOOD: Strong bcrypt hashing
|
|
91
|
+
import bcrypt from 'bcrypt';
|
|
92
|
+
const hash = await bcrypt.hash(password, 12); // 12+ rounds
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Automated Scan**:
|
|
96
|
+
```bash
|
|
97
|
+
# Find weak crypto usage
|
|
98
|
+
grep -rn "md5\|sha1\|createHash('sha1')" src/ && \
|
|
99
|
+
echo "⚠️ Weak hashing detected"
|
|
100
|
+
|
|
101
|
+
# Find hardcoded secrets
|
|
102
|
+
grep -rn "api[_-]?key\s*=\s*['\"][a-zA-Z0-9]" src/ && \
|
|
103
|
+
echo "⚠️ Hardcoded API key detected"
|
|
104
|
+
|
|
105
|
+
# Find bcrypt with low rounds
|
|
106
|
+
grep -rn "bcrypt\.hash.*,\s*[0-9])" src/ | grep -v "1[0-9]" && \
|
|
107
|
+
echo "⚠️ Insufficient bcrypt rounds"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 3. Injection Vulnerabilities
|
|
113
|
+
|
|
114
|
+
**Check for**:
|
|
115
|
+
- SQL injection (unparameterized queries)
|
|
116
|
+
- NoSQL injection (unvalidated MongoDB queries)
|
|
117
|
+
- Command injection (shell commands with user input)
|
|
118
|
+
- XSS (unescaped user content)
|
|
119
|
+
|
|
120
|
+
**Example Vulnerable Code**:
|
|
121
|
+
```typescript
|
|
122
|
+
// ❌ BAD: SQL injection
|
|
123
|
+
const query = `SELECT * FROM users WHERE email = '${userInput}'`;
|
|
124
|
+
db.query(query);
|
|
125
|
+
|
|
126
|
+
// ❌ BAD: Command injection
|
|
127
|
+
exec(`convert ${userFilename} output.jpg`);
|
|
128
|
+
|
|
129
|
+
// ❌ BAD: NoSQL injection
|
|
130
|
+
User.findOne({ email: req.body.email });
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Secure Alternatives**:
|
|
134
|
+
```typescript
|
|
135
|
+
// ✅ GOOD: Parameterized SQL query
|
|
136
|
+
const query = 'SELECT * FROM users WHERE email = $1';
|
|
137
|
+
db.query(query, [userInput]);
|
|
138
|
+
|
|
139
|
+
// ✅ GOOD: Validate filename, no shell execution
|
|
140
|
+
const safeFilename = path.basename(userFilename);
|
|
141
|
+
sharp(safeFilename).toFile('output.jpg');
|
|
142
|
+
|
|
143
|
+
// ✅ GOOD: Validate with Zod schema
|
|
144
|
+
const EmailSchema = z.object({ email: z.string().email() });
|
|
145
|
+
const { email } = EmailSchema.parse(req.body);
|
|
146
|
+
User.findOne({ email });
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Automated Scan**:
|
|
150
|
+
```bash
|
|
151
|
+
# Find potential SQL injection
|
|
152
|
+
grep -rn "query.*\${.*}" src/server/ && \
|
|
153
|
+
echo "⚠️ Potential SQL injection (template literals)"
|
|
154
|
+
|
|
155
|
+
# Find command execution with user input
|
|
156
|
+
grep -rn "exec\|spawn\|execSync" src/ | \
|
|
157
|
+
grep -v "// safe:" && \
|
|
158
|
+
echo "⚠️ Potential command injection"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### 4. Insecure Design
|
|
164
|
+
|
|
165
|
+
**Check for**:
|
|
166
|
+
- Missing rate limiting on sensitive endpoints
|
|
167
|
+
- No CSRF protection
|
|
168
|
+
- Insecure session management
|
|
169
|
+
- Missing security headers
|
|
170
|
+
|
|
171
|
+
**Secure Patterns**:
|
|
172
|
+
```typescript
|
|
173
|
+
// ✅ Rate limiting
|
|
174
|
+
import rateLimit from 'express-rate-limit';
|
|
175
|
+
|
|
176
|
+
const loginLimiter = rateLimit({
|
|
177
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
178
|
+
max: 5, // 5 attempts
|
|
179
|
+
message: 'Too many login attempts'
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
router.post('/api/auth/login', loginLimiter, loginHandler);
|
|
183
|
+
|
|
184
|
+
// ✅ Security headers
|
|
185
|
+
import helmet from 'helmet';
|
|
186
|
+
app.use(helmet());
|
|
187
|
+
|
|
188
|
+
// ✅ CSRF protection
|
|
189
|
+
import csrf from 'csurf';
|
|
190
|
+
app.use(csrf({ cookie: true }));
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### 5. Security Misconfiguration
|
|
196
|
+
|
|
197
|
+
**Check for**:
|
|
198
|
+
- Debug mode enabled in production
|
|
199
|
+
- Default credentials
|
|
200
|
+
- Unnecessary features enabled
|
|
201
|
+
- Verbose error messages exposing internals
|
|
202
|
+
|
|
203
|
+
**Secure Configuration**:
|
|
204
|
+
```typescript
|
|
205
|
+
// ✅ Environment-specific error handling
|
|
206
|
+
app.use((err, req, res, next) => {
|
|
207
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
208
|
+
|
|
209
|
+
res.status(err.status || 500).json({
|
|
210
|
+
error: err.message,
|
|
211
|
+
// Only show stack in development
|
|
212
|
+
...(isDev && { stack: err.stack })
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// ✅ Disable unnecessary features
|
|
217
|
+
app.disable('x-powered-by');
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Automated Scan**:
|
|
221
|
+
```bash
|
|
222
|
+
# Find debug code
|
|
223
|
+
grep -rn "console\.log\|debugger" src/ && \
|
|
224
|
+
echo "⚠️ Debug code in production"
|
|
225
|
+
|
|
226
|
+
# Find exposed secrets in error messages
|
|
227
|
+
grep -rn "throw.*password\|throw.*token\|throw.*secret" src/ && \
|
|
228
|
+
echo "⚠️ Potential secret exposure in errors"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### 6. Vulnerable and Outdated Components
|
|
234
|
+
|
|
235
|
+
**Check for**:
|
|
236
|
+
- Outdated npm packages with known vulnerabilities
|
|
237
|
+
- Unused dependencies
|
|
238
|
+
|
|
239
|
+
**Automated Scan**:
|
|
240
|
+
```bash
|
|
241
|
+
# Check for vulnerabilities
|
|
242
|
+
npm audit --audit-level=moderate
|
|
243
|
+
|
|
244
|
+
# Check for outdated packages
|
|
245
|
+
npm outdated
|
|
246
|
+
|
|
247
|
+
# Check unused dependencies
|
|
248
|
+
npx depcheck
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### 7. Identification and Authentication Failures
|
|
254
|
+
|
|
255
|
+
**Check for**:
|
|
256
|
+
- Weak password requirements
|
|
257
|
+
- No multi-factor authentication option
|
|
258
|
+
- Session fixation vulnerabilities
|
|
259
|
+
- Insufficient session timeout
|
|
260
|
+
|
|
261
|
+
**Secure Password Validation**:
|
|
262
|
+
```typescript
|
|
263
|
+
// ✅ Strong password requirements
|
|
264
|
+
const PasswordSchema = z.string()
|
|
265
|
+
.min(12, 'Password must be at least 12 characters')
|
|
266
|
+
.regex(/[A-Z]/, 'Must contain uppercase letter')
|
|
267
|
+
.regex(/[a-z]/, 'Must contain lowercase letter')
|
|
268
|
+
.regex(/[0-9]/, 'Must contain number')
|
|
269
|
+
.regex(/[^A-Za-z0-9]/, 'Must contain special character');
|
|
270
|
+
|
|
271
|
+
// ✅ Session configuration
|
|
272
|
+
app.use(session({
|
|
273
|
+
secret: process.env.SESSION_SECRET,
|
|
274
|
+
resave: false,
|
|
275
|
+
saveUninitialized: false,
|
|
276
|
+
cookie: {
|
|
277
|
+
secure: true, // HTTPS only
|
|
278
|
+
httpOnly: true, // No JavaScript access
|
|
279
|
+
maxAge: 15 * 60 * 1000, // 15 minutes
|
|
280
|
+
sameSite: 'strict' // CSRF protection
|
|
281
|
+
}
|
|
282
|
+
}));
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### 8. Software and Data Integrity Failures
|
|
288
|
+
|
|
289
|
+
**Check for**:
|
|
290
|
+
- Unsigned/unverified packages
|
|
291
|
+
- No integrity checks on uploaded files
|
|
292
|
+
- Insecure deserialization
|
|
293
|
+
|
|
294
|
+
**Secure File Upload**:
|
|
295
|
+
```typescript
|
|
296
|
+
// ✅ Validate file type and size
|
|
297
|
+
import multer from 'multer';
|
|
298
|
+
import fileType from 'file-type';
|
|
299
|
+
|
|
300
|
+
const upload = multer({
|
|
301
|
+
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB max
|
|
302
|
+
fileFilter: async (req, file, cb) => {
|
|
303
|
+
// Check MIME type
|
|
304
|
+
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
|
|
305
|
+
if (!allowedTypes.includes(file.mimetype)) {
|
|
306
|
+
return cb(new Error('Invalid file type'));
|
|
307
|
+
}
|
|
308
|
+
cb(null, true);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Verify actual file type (not just extension)
|
|
313
|
+
router.post('/upload', upload.single('file'), async (req, res) => {
|
|
314
|
+
const type = await fileType.fromBuffer(req.file.buffer);
|
|
315
|
+
if (!type || !['jpg', 'png', 'gif'].includes(type.ext)) {
|
|
316
|
+
throw new AppError('Invalid file type', 400);
|
|
317
|
+
}
|
|
318
|
+
// Process file...
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
### 9. Security Logging and Monitoring Failures
|
|
325
|
+
|
|
326
|
+
**Check for**:
|
|
327
|
+
- No audit logging for sensitive operations
|
|
328
|
+
- Missing security event monitoring
|
|
329
|
+
- No alerting for suspicious activity
|
|
330
|
+
|
|
331
|
+
**Secure Logging**:
|
|
332
|
+
```typescript
|
|
333
|
+
// ✅ Audit logging
|
|
334
|
+
import winston from 'winston';
|
|
335
|
+
|
|
336
|
+
const auditLogger = winston.createLogger({
|
|
337
|
+
transports: [
|
|
338
|
+
new winston.transports.File({ filename: 'audit.log' })
|
|
339
|
+
]
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Log security events
|
|
343
|
+
function auditLog(event: string, details: object) {
|
|
344
|
+
auditLogger.info({
|
|
345
|
+
timestamp: new Date().toISOString(),
|
|
346
|
+
event,
|
|
347
|
+
...details,
|
|
348
|
+
// Never log passwords or tokens!
|
|
349
|
+
...sanitizeSecrets(details)
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Usage
|
|
354
|
+
router.post('/api/auth/login', async (req, res) => {
|
|
355
|
+
const { email } = req.body;
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const result = await login(email, password);
|
|
359
|
+
auditLog('LOGIN_SUCCESS', { email, ip: req.ip });
|
|
360
|
+
res.json(result);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
auditLog('LOGIN_FAILURE', { email, ip: req.ip, reason: err.message });
|
|
363
|
+
throw err;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### 10. Server-Side Request Forgery (SSRF)
|
|
371
|
+
|
|
372
|
+
**Check for**:
|
|
373
|
+
- Unvalidated URL fetching
|
|
374
|
+
- Internal network access from user input
|
|
375
|
+
- Open redirects
|
|
376
|
+
|
|
377
|
+
**Secure URL Fetching**:
|
|
378
|
+
```typescript
|
|
379
|
+
// ✅ Validate and whitelist URLs
|
|
380
|
+
const ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com'];
|
|
381
|
+
|
|
382
|
+
function validateUrl(url: string): boolean {
|
|
383
|
+
try {
|
|
384
|
+
const parsed = new URL(url);
|
|
385
|
+
|
|
386
|
+
// Block private IPs
|
|
387
|
+
const privateIpRanges = ['127.', '10.', '172.16.', '192.168.', 'localhost'];
|
|
388
|
+
if (privateIpRanges.some(range => parsed.hostname.startsWith(range))) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Whitelist domains
|
|
393
|
+
return ALLOWED_DOMAINS.includes(parsed.hostname);
|
|
394
|
+
} catch {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
router.post('/fetch', async (req, res) => {
|
|
400
|
+
const { url } = req.body;
|
|
401
|
+
|
|
402
|
+
if (!validateUrl(url)) {
|
|
403
|
+
throw new AppError('Invalid URL', 400);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const response = await fetch(url);
|
|
407
|
+
res.json(await response.json());
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Automated Security Scan Script
|
|
414
|
+
|
|
415
|
+
Create `scripts/security-scan.sh`:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
#!/bin/bash
|
|
419
|
+
|
|
420
|
+
echo "🔍 Running Security Scan..."
|
|
421
|
+
echo ""
|
|
422
|
+
|
|
423
|
+
# 1. NPM Audit
|
|
424
|
+
echo "1. Checking dependencies for vulnerabilities..."
|
|
425
|
+
npm audit --audit-level=moderate || echo "⚠️ Vulnerabilities found"
|
|
426
|
+
echo ""
|
|
427
|
+
|
|
428
|
+
# 2. Find hardcoded secrets
|
|
429
|
+
echo "2. Scanning for hardcoded secrets..."
|
|
430
|
+
grep -rn "password\s*=\s*['\"]" src/ --exclude-dir=node_modules && \
|
|
431
|
+
echo "⚠️ Hardcoded passwords detected" || echo "✅ No hardcoded passwords"
|
|
432
|
+
echo ""
|
|
433
|
+
|
|
434
|
+
# 3. Find weak crypto
|
|
435
|
+
echo "3. Checking for weak cryptography..."
|
|
436
|
+
grep -rn "md5\|sha1" src/ --exclude-dir=node_modules && \
|
|
437
|
+
echo "⚠️ Weak hashing detected" || echo "✅ Strong crypto only"
|
|
438
|
+
echo ""
|
|
439
|
+
|
|
440
|
+
# 4. Find SQL injection risks
|
|
441
|
+
echo "4. Checking for SQL injection risks..."
|
|
442
|
+
grep -rn "query.*\${" src/ --exclude-dir=node_modules && \
|
|
443
|
+
echo "⚠️ Template literals in queries (injection risk)" || echo "✅ No injection risks"
|
|
444
|
+
echo ""
|
|
445
|
+
|
|
446
|
+
# 5. Check authentication
|
|
447
|
+
echo "5. Checking route authentication..."
|
|
448
|
+
grep -rn "router\.\(get\|post\|put\|delete\)" src/server/routes/ | \
|
|
449
|
+
grep -v "requireAuth\|public" | wc -l | \
|
|
450
|
+
xargs -I {} echo "⚠️ {} routes without auth middleware"
|
|
451
|
+
echo ""
|
|
452
|
+
|
|
453
|
+
# 6. Check for debug code
|
|
454
|
+
echo "6. Checking for debug code..."
|
|
455
|
+
grep -rn "console\.log\|debugger" src/ --exclude-dir=node_modules | wc -l | \
|
|
456
|
+
xargs -I {} echo "⚠️ {} instances of debug code"
|
|
457
|
+
echo ""
|
|
458
|
+
|
|
459
|
+
echo "✅ Security scan complete"
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Make executable:
|
|
463
|
+
```bash
|
|
464
|
+
chmod +x scripts/security-scan.sh
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Integration with Code Review
|
|
470
|
+
|
|
471
|
+
When the `code-reviewer` agent is invoked, this skill provides:
|
|
472
|
+
|
|
473
|
+
1. **Automated scans** via the security-scan script
|
|
474
|
+
2. **Manual checklist** for OWASP Top 10
|
|
475
|
+
3. **Remediation guidance** for each vulnerability type
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Common Vulnerabilities by File Type
|
|
480
|
+
|
|
481
|
+
### Frontend (React/TypeScript)
|
|
482
|
+
|
|
483
|
+
**XSS Vulnerabilities**:
|
|
484
|
+
```typescript
|
|
485
|
+
// ❌ BAD: dangerouslySetInnerHTML without sanitization
|
|
486
|
+
<div dangerouslySetInnerHTML={{ __html: userContent }} />
|
|
487
|
+
|
|
488
|
+
// ✅ GOOD: Sanitize with DOMPurify
|
|
489
|
+
import DOMPurify from 'dompurify';
|
|
490
|
+
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Open Redirects**:
|
|
494
|
+
```typescript
|
|
495
|
+
// ❌ BAD: Unvalidated redirect
|
|
496
|
+
router.push(req.query.redirect);
|
|
497
|
+
|
|
498
|
+
// ✅ GOOD: Whitelist allowed paths
|
|
499
|
+
const ALLOWED_REDIRECTS = ['/dashboard', '/profile', '/settings'];
|
|
500
|
+
const redirect = req.query.redirect;
|
|
501
|
+
if (ALLOWED_REDIRECTS.includes(redirect)) {
|
|
502
|
+
router.push(redirect);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Backend (Node.js/Express)
|
|
507
|
+
|
|
508
|
+
**Authentication Bypass**:
|
|
509
|
+
```typescript
|
|
510
|
+
// ❌ BAD: Weak token validation
|
|
511
|
+
if (req.headers.authorization) {
|
|
512
|
+
req.user = decodeToken(req.headers.authorization);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// ✅ GOOD: Verify signature
|
|
516
|
+
import jwt from 'jsonwebtoken';
|
|
517
|
+
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
518
|
+
req.user = jwt.verify(token, process.env.JWT_SECRET);
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Security Tools Integration
|
|
524
|
+
|
|
525
|
+
### ESLint Security Plugin
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
npm install --save-dev eslint-plugin-security
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
```json
|
|
532
|
+
// .eslintrc.json
|
|
533
|
+
{
|
|
534
|
+
"plugins": ["security"],
|
|
535
|
+
"extends": ["plugin:security/recommended"]
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### SAST Tools
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
# Snyk
|
|
543
|
+
npx snyk test
|
|
544
|
+
|
|
545
|
+
# CodeQL (GitHub)
|
|
546
|
+
# Configure in .github/workflows/codeql.yml
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Remember
|
|
552
|
+
|
|
553
|
+
- **Security is not optional** - Always validate inputs
|
|
554
|
+
- **Trust nothing from users** - Sanitize, validate, escape
|
|
555
|
+
- **Defense in depth** - Multiple layers of security
|
|
556
|
+
- **Principle of least privilege** - Minimal permissions
|
|
557
|
+
- **Audit everything** - Log security events
|
|
558
|
+
- **Keep dependencies updated** - Regular `npm audit`
|
|
559
|
+
- **HTTPS everywhere** - Encrypt in transit
|
|
560
|
+
- **Hash, don't encrypt** - For passwords, use bcrypt
|