vibesafu 0.1.3 → 0.1.6
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/README.md +33 -0
- package/dist/index.js +569 -130
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -218,6 +218,39 @@ pnpm build
|
|
|
218
218
|
pnpm verify
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
+
## Security Model
|
|
222
|
+
|
|
223
|
+
### What VibeSafu Protects Against
|
|
224
|
+
|
|
225
|
+
VibeSafu provides **pre-execution review** of commands. It analyzes commands before they run and blocks dangerous patterns:
|
|
226
|
+
|
|
227
|
+
- **Prompt Injection Attacks**: Blocks attempts to manipulate Claude into running malicious code
|
|
228
|
+
- **Supply Chain Attacks**: Forces review of package installations and untrusted scripts
|
|
229
|
+
- **Data Exfiltration**: Blocks commands that try to send sensitive data to external servers
|
|
230
|
+
- **Reverse Shells**: Instant-blocks common reverse shell patterns
|
|
231
|
+
- **Crypto Mining**: Blocks cryptocurrency mining commands
|
|
232
|
+
|
|
233
|
+
### What VibeSafu Does NOT Protect Against
|
|
234
|
+
|
|
235
|
+
VibeSafu is a **static pre-execution analyzer**, not a runtime sandbox. It cannot protect against:
|
|
236
|
+
|
|
237
|
+
| Limitation | Description | Recommendation |
|
|
238
|
+
|------------|-------------|----------------|
|
|
239
|
+
| **TOCTOU Attacks** | File modified between analysis and execution | Use Docker/firejail sandbox |
|
|
240
|
+
| **Environment Manipulation** | PATH, LD_PRELOAD, alias poisoning | Use isolated environments |
|
|
241
|
+
| **Multi-stage Chains** | Only 1st level of downloads analyzed | Review scripts manually |
|
|
242
|
+
| **Conditional Malware** | Code behaving differently based on environment | Use runtime monitoring |
|
|
243
|
+
| **Runtime Exploits** | Vulnerabilities in executed code | Use security scanning tools |
|
|
244
|
+
|
|
245
|
+
### Defense in Depth
|
|
246
|
+
|
|
247
|
+
For maximum security, combine VibeSafu with:
|
|
248
|
+
|
|
249
|
+
1. **Sandbox** (Docker, firejail) - Isolates execution environment
|
|
250
|
+
2. **Network Monitoring** - Detects suspicious outbound connections
|
|
251
|
+
3. **File Integrity** - Monitors file changes
|
|
252
|
+
4. **Code Review** - Manual review of downloaded scripts
|
|
253
|
+
|
|
221
254
|
## FAQ
|
|
222
255
|
|
|
223
256
|
### Do I need an Anthropic API key?
|
package/dist/index.js
CHANGED
|
@@ -166,348 +166,462 @@ async function getApiKey() {
|
|
|
166
166
|
import Anthropic from "@anthropic-ai/sdk";
|
|
167
167
|
|
|
168
168
|
// src/config/patterns.ts
|
|
169
|
+
var REVERSE_SHELL_RISK = "Remote attacker gains complete control of your system";
|
|
170
|
+
var REVERSE_SHELL_LEGIT = ["Penetration testing", "CTF challenges", "Security research"];
|
|
169
171
|
var REVERSE_SHELL_PATTERNS = [
|
|
170
172
|
// Bash variants
|
|
171
173
|
{
|
|
172
174
|
name: "bash_reverse_shell",
|
|
173
175
|
pattern: /bash\s+-i\s+>&\s*\/dev\/tcp/i,
|
|
174
176
|
severity: "critical",
|
|
175
|
-
description: "Bash reverse shell via /dev/tcp"
|
|
177
|
+
description: "Bash reverse shell via /dev/tcp",
|
|
178
|
+
risk: REVERSE_SHELL_RISK,
|
|
179
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
176
180
|
},
|
|
177
181
|
{
|
|
178
182
|
name: "sh_reverse_shell",
|
|
179
183
|
pattern: /\bsh\s+-i\s+>&\s*\/dev\/tcp/i,
|
|
180
184
|
severity: "critical",
|
|
181
|
-
description: "sh reverse shell via /dev/tcp"
|
|
185
|
+
description: "sh reverse shell via /dev/tcp",
|
|
186
|
+
risk: REVERSE_SHELL_RISK,
|
|
187
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
182
188
|
},
|
|
183
189
|
{
|
|
184
190
|
name: "zsh_reverse_shell",
|
|
185
191
|
pattern: /zsh\s+-i\s+>&\s*\/dev\/tcp/i,
|
|
186
192
|
severity: "critical",
|
|
187
|
-
description: "Zsh reverse shell via /dev/tcp"
|
|
193
|
+
description: "Zsh reverse shell via /dev/tcp",
|
|
194
|
+
risk: REVERSE_SHELL_RISK,
|
|
195
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
188
196
|
},
|
|
189
197
|
{
|
|
190
198
|
name: "ksh_reverse_shell",
|
|
191
199
|
pattern: /ksh\s+-i\s+>&\s*\/dev\/tcp/i,
|
|
192
200
|
severity: "critical",
|
|
193
|
-
description: "Ksh reverse shell via /dev/tcp"
|
|
201
|
+
description: "Ksh reverse shell via /dev/tcp",
|
|
202
|
+
risk: REVERSE_SHELL_RISK,
|
|
203
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
194
204
|
},
|
|
195
205
|
{
|
|
196
206
|
name: "dash_reverse_shell",
|
|
197
207
|
pattern: /dash\s+-i\s+>&\s*\/dev\/tcp/i,
|
|
198
208
|
severity: "critical",
|
|
199
|
-
description: "Dash reverse shell via /dev/tcp"
|
|
209
|
+
description: "Dash reverse shell via /dev/tcp",
|
|
210
|
+
risk: REVERSE_SHELL_RISK,
|
|
211
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
200
212
|
},
|
|
201
213
|
// Generic /dev/tcp pattern (catches variable expansion bypasses)
|
|
202
214
|
{
|
|
203
215
|
name: "dev_tcp_redirect",
|
|
204
216
|
pattern: />\s*&?\s*\/dev\/tcp\//i,
|
|
205
217
|
severity: "critical",
|
|
206
|
-
description: "Redirection to /dev/tcp (reverse shell indicator)"
|
|
218
|
+
description: "Redirection to /dev/tcp (reverse shell indicator)",
|
|
219
|
+
risk: REVERSE_SHELL_RISK,
|
|
220
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
207
221
|
},
|
|
208
222
|
// Netcat variants
|
|
209
223
|
{
|
|
210
224
|
name: "netcat_reverse_shell",
|
|
211
225
|
pattern: /nc\s+.*-e\s+(\/bin\/)?(ba)?sh/i,
|
|
212
226
|
severity: "critical",
|
|
213
|
-
description: "Netcat reverse shell with -e flag"
|
|
227
|
+
description: "Netcat reverse shell with -e flag",
|
|
228
|
+
risk: REVERSE_SHELL_RISK,
|
|
229
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
214
230
|
},
|
|
215
231
|
{
|
|
216
232
|
name: "netcat_c_flag",
|
|
217
233
|
pattern: /nc\s+.*-c\s+(\/bin\/)?(ba)?sh/i,
|
|
218
234
|
severity: "critical",
|
|
219
|
-
description: "Netcat reverse shell with -c flag"
|
|
235
|
+
description: "Netcat reverse shell with -c flag",
|
|
236
|
+
risk: REVERSE_SHELL_RISK,
|
|
237
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
220
238
|
},
|
|
221
239
|
{
|
|
222
240
|
name: "ncat_reverse_shell",
|
|
223
241
|
pattern: /ncat\s+.*-e\s+(\/bin\/)?(ba)?sh/i,
|
|
224
242
|
severity: "critical",
|
|
225
|
-
description: "Ncat reverse shell"
|
|
243
|
+
description: "Ncat reverse shell",
|
|
244
|
+
risk: REVERSE_SHELL_RISK,
|
|
245
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
226
246
|
},
|
|
227
247
|
// Python reverse shells
|
|
228
248
|
{
|
|
229
249
|
name: "python_reverse_shell",
|
|
230
250
|
pattern: /python[23]?\s+.*-c\s+.*socket.*connect/i,
|
|
231
251
|
severity: "critical",
|
|
232
|
-
description: "Python socket-based reverse shell"
|
|
252
|
+
description: "Python socket-based reverse shell",
|
|
253
|
+
risk: REVERSE_SHELL_RISK,
|
|
254
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
233
255
|
},
|
|
234
256
|
{
|
|
235
257
|
name: "python_pty_shell",
|
|
236
258
|
pattern: /python[23]?\s+.*-c\s+.*pty\.spawn/i,
|
|
237
259
|
severity: "critical",
|
|
238
|
-
description: "Python PTY spawn (shell upgrade)"
|
|
260
|
+
description: "Python PTY spawn (shell upgrade)",
|
|
261
|
+
risk: REVERSE_SHELL_RISK,
|
|
262
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
239
263
|
},
|
|
240
264
|
// Perl reverse shell
|
|
241
265
|
{
|
|
242
266
|
name: "perl_reverse_shell",
|
|
243
267
|
pattern: /perl\s+.*(-e\s+.*)?(['"])?use\s+Socket/i,
|
|
244
268
|
severity: "critical",
|
|
245
|
-
description: "Perl socket-based reverse shell"
|
|
269
|
+
description: "Perl socket-based reverse shell",
|
|
270
|
+
risk: REVERSE_SHELL_RISK,
|
|
271
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
246
272
|
},
|
|
247
273
|
// Ruby reverse shell
|
|
248
274
|
{
|
|
249
275
|
name: "ruby_reverse_shell",
|
|
250
276
|
pattern: /ruby\s+.*-rsocket\s+-e/i,
|
|
251
277
|
severity: "critical",
|
|
252
|
-
description: "Ruby socket-based reverse shell"
|
|
278
|
+
description: "Ruby socket-based reverse shell",
|
|
279
|
+
risk: REVERSE_SHELL_RISK,
|
|
280
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
253
281
|
},
|
|
254
282
|
{
|
|
255
283
|
name: "ruby_socket_reverse",
|
|
256
284
|
pattern: /ruby\s+.*-e\s+.*TCPSocket/i,
|
|
257
285
|
severity: "critical",
|
|
258
|
-
description: "Ruby TCPSocket reverse shell"
|
|
286
|
+
description: "Ruby TCPSocket reverse shell",
|
|
287
|
+
risk: REVERSE_SHELL_RISK,
|
|
288
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
259
289
|
},
|
|
260
290
|
// PHP reverse shell
|
|
261
291
|
{
|
|
262
292
|
name: "php_reverse_shell",
|
|
263
293
|
pattern: /php\s+.*-r\s+.*fsockopen/i,
|
|
264
294
|
severity: "critical",
|
|
265
|
-
description: "PHP fsockopen reverse shell"
|
|
295
|
+
description: "PHP fsockopen reverse shell",
|
|
296
|
+
risk: REVERSE_SHELL_RISK,
|
|
297
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
266
298
|
},
|
|
267
299
|
// Socat
|
|
268
300
|
{
|
|
269
301
|
name: "socat_reverse_shell",
|
|
270
302
|
pattern: /socat\s+.*exec.*sh/i,
|
|
271
303
|
severity: "critical",
|
|
272
|
-
description: "Socat reverse shell"
|
|
304
|
+
description: "Socat reverse shell",
|
|
305
|
+
risk: REVERSE_SHELL_RISK,
|
|
306
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
273
307
|
},
|
|
274
308
|
// Telnet reverse shell
|
|
275
309
|
{
|
|
276
310
|
name: "telnet_reverse_shell",
|
|
277
311
|
pattern: /telnet\s+.*\|\s*\/bin\/(ba)?sh/i,
|
|
278
312
|
severity: "critical",
|
|
279
|
-
description: "Telnet-based reverse shell"
|
|
313
|
+
description: "Telnet-based reverse shell",
|
|
314
|
+
risk: REVERSE_SHELL_RISK,
|
|
315
|
+
legitimateUses: REVERSE_SHELL_LEGIT
|
|
280
316
|
}
|
|
281
317
|
];
|
|
318
|
+
var DATA_EXFIL_RISK = "Sensitive data (API keys, secrets, credentials) sent to external server";
|
|
319
|
+
var DATA_EXFIL_LEGIT = ["Sending auth headers to your own API", "Debugging with trusted services"];
|
|
282
320
|
var DATA_EXFIL_PATTERNS = [
|
|
283
321
|
// Environment variable exfiltration via curl
|
|
284
322
|
{
|
|
285
323
|
name: "curl_api_key",
|
|
286
324
|
pattern: /curl.*\$\{?[A-Z_]*KEY/i,
|
|
287
325
|
severity: "critical",
|
|
288
|
-
description: "curl with API key environment variable"
|
|
326
|
+
description: "curl with API key environment variable",
|
|
327
|
+
risk: DATA_EXFIL_RISK,
|
|
328
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
289
329
|
},
|
|
290
330
|
{
|
|
291
331
|
name: "curl_secret",
|
|
292
332
|
pattern: /curl.*\$\{?[A-Z_]*SECRET/i,
|
|
293
333
|
severity: "critical",
|
|
294
|
-
description: "curl with secret environment variable"
|
|
334
|
+
description: "curl with secret environment variable",
|
|
335
|
+
risk: DATA_EXFIL_RISK,
|
|
336
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
295
337
|
},
|
|
296
338
|
{
|
|
297
339
|
name: "curl_token",
|
|
298
340
|
pattern: /curl.*\$\{?[A-Z_]*TOKEN/i,
|
|
299
341
|
severity: "critical",
|
|
300
|
-
description: "curl with token environment variable"
|
|
342
|
+
description: "curl with token environment variable",
|
|
343
|
+
risk: DATA_EXFIL_RISK,
|
|
344
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
301
345
|
},
|
|
302
346
|
{
|
|
303
347
|
name: "curl_password",
|
|
304
348
|
pattern: /curl.*\$\{?[A-Z_]*PASSWORD/i,
|
|
305
349
|
severity: "critical",
|
|
306
|
-
description: "curl with password environment variable"
|
|
350
|
+
description: "curl with password environment variable",
|
|
351
|
+
risk: DATA_EXFIL_RISK,
|
|
352
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
307
353
|
},
|
|
308
354
|
{
|
|
309
355
|
name: "curl_credential",
|
|
310
356
|
pattern: /curl.*\$\{?[A-Z_]*CREDENTIAL/i,
|
|
311
357
|
severity: "critical",
|
|
312
|
-
description: "curl with credential environment variable"
|
|
358
|
+
description: "curl with credential environment variable",
|
|
359
|
+
risk: DATA_EXFIL_RISK,
|
|
360
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
313
361
|
},
|
|
314
362
|
// Environment variable exfiltration via wget
|
|
315
363
|
{
|
|
316
364
|
name: "wget_key",
|
|
317
365
|
pattern: /wget.*\$\{?[A-Z_]*KEY/i,
|
|
318
366
|
severity: "critical",
|
|
319
|
-
description: "wget with API key environment variable"
|
|
367
|
+
description: "wget with API key environment variable",
|
|
368
|
+
risk: DATA_EXFIL_RISK,
|
|
369
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
320
370
|
},
|
|
321
371
|
{
|
|
322
372
|
name: "wget_secret",
|
|
323
373
|
pattern: /wget.*\$\{?[A-Z_]*SECRET/i,
|
|
324
374
|
severity: "critical",
|
|
325
|
-
description: "wget with secret environment variable"
|
|
375
|
+
description: "wget with secret environment variable",
|
|
376
|
+
risk: DATA_EXFIL_RISK,
|
|
377
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
326
378
|
},
|
|
327
379
|
{
|
|
328
380
|
name: "wget_token",
|
|
329
381
|
pattern: /wget.*\$\{?[A-Z_]*TOKEN/i,
|
|
330
382
|
severity: "critical",
|
|
331
|
-
description: "wget with token environment variable"
|
|
383
|
+
description: "wget with token environment variable",
|
|
384
|
+
risk: DATA_EXFIL_RISK,
|
|
385
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
332
386
|
},
|
|
333
387
|
// POST data with env vars
|
|
334
388
|
{
|
|
335
389
|
name: "curl_data_env",
|
|
336
390
|
pattern: /curl\s+.*(-d|--data|--data-raw)\s+.*\$\{?[A-Z_]/i,
|
|
337
391
|
severity: "critical",
|
|
338
|
-
description: "curl POST with environment variable in data"
|
|
392
|
+
description: "curl POST with environment variable in data",
|
|
393
|
+
risk: DATA_EXFIL_RISK,
|
|
394
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
339
395
|
},
|
|
340
396
|
{
|
|
341
397
|
name: "curl_header_env",
|
|
342
398
|
pattern: /curl\s+.*(-H|--header)\s+.*\$\{?[A-Z_]/i,
|
|
343
399
|
severity: "critical",
|
|
344
|
-
description: "curl with environment variable in header"
|
|
400
|
+
description: "curl with environment variable in header",
|
|
401
|
+
risk: DATA_EXFIL_RISK,
|
|
402
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
345
403
|
},
|
|
346
404
|
{
|
|
347
405
|
name: "wget_post_env",
|
|
348
406
|
pattern: /wget\s+.*--post-data.*\$\{?[A-Z_]/i,
|
|
349
407
|
severity: "critical",
|
|
350
|
-
description: "wget POST with environment variable"
|
|
408
|
+
description: "wget POST with environment variable",
|
|
409
|
+
risk: DATA_EXFIL_RISK,
|
|
410
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
351
411
|
},
|
|
352
412
|
{
|
|
353
413
|
name: "wget_header_env",
|
|
354
414
|
pattern: /wget\s+.*--header.*\$\{?[A-Z_]/i,
|
|
355
415
|
severity: "critical",
|
|
356
|
-
description: "wget with environment variable in header"
|
|
416
|
+
description: "wget with environment variable in header",
|
|
417
|
+
risk: DATA_EXFIL_RISK,
|
|
418
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
357
419
|
},
|
|
358
420
|
// Full environment dump
|
|
359
421
|
{
|
|
360
422
|
name: "env_pipe_curl",
|
|
361
423
|
pattern: /\benv\b.*\|\s*curl/i,
|
|
362
424
|
severity: "critical",
|
|
363
|
-
description: "Environment dump piped to curl"
|
|
425
|
+
description: "Environment dump piped to curl",
|
|
426
|
+
risk: "All environment variables (including secrets) sent to external server",
|
|
427
|
+
legitimateUses: ["Debugging in controlled environment"]
|
|
364
428
|
},
|
|
365
429
|
{
|
|
366
430
|
name: "printenv_pipe",
|
|
367
431
|
pattern: /printenv.*\|\s*(curl|nc|wget)/i,
|
|
368
432
|
severity: "critical",
|
|
369
|
-
description: "Printenv piped to network command"
|
|
433
|
+
description: "Printenv piped to network command",
|
|
434
|
+
risk: "All environment variables sent to external server",
|
|
435
|
+
legitimateUses: ["Debugging in controlled environment"]
|
|
370
436
|
},
|
|
371
437
|
{
|
|
372
438
|
name: "env_pipe_nc",
|
|
373
439
|
pattern: /\benv\b.*\|\s*nc\b/i,
|
|
374
440
|
severity: "critical",
|
|
375
|
-
description: "Environment dump piped to netcat"
|
|
441
|
+
description: "Environment dump piped to netcat",
|
|
442
|
+
risk: "All environment variables sent to external server",
|
|
443
|
+
legitimateUses: ["Debugging in controlled environment"]
|
|
376
444
|
},
|
|
377
445
|
// Sensitive file exfiltration
|
|
378
446
|
{
|
|
379
447
|
name: "ssh_key_exfil",
|
|
380
448
|
pattern: /cat\s+.*\.ssh\/(id_rsa|id_ed25519|id_dsa).*\|\s*(curl|nc|wget)/i,
|
|
381
449
|
severity: "critical",
|
|
382
|
-
description: "SSH private key exfiltration"
|
|
450
|
+
description: "SSH private key exfiltration",
|
|
451
|
+
risk: "SSH private key sent to external server - attacker can access your servers",
|
|
452
|
+
legitimateUses: ["Backing up keys to your own secure storage"]
|
|
383
453
|
},
|
|
384
454
|
{
|
|
385
455
|
name: "aws_creds_exfil",
|
|
386
456
|
pattern: /cat\s+.*\.aws\/(credentials|config).*\|\s*(curl|nc|wget)/i,
|
|
387
457
|
severity: "critical",
|
|
388
|
-
description: "AWS credentials exfiltration"
|
|
458
|
+
description: "AWS credentials exfiltration",
|
|
459
|
+
risk: "AWS credentials sent to external server - attacker gains cloud access",
|
|
460
|
+
legitimateUses: ["Backing up config to your own secure storage"]
|
|
389
461
|
},
|
|
390
462
|
{
|
|
391
463
|
name: "file_stdin_curl",
|
|
392
464
|
pattern: /curl\s+.*-d\s*@-/i,
|
|
393
465
|
severity: "high",
|
|
394
|
-
description: "curl reading from stdin (potential data exfil)"
|
|
466
|
+
description: "curl reading from stdin (potential data exfil)",
|
|
467
|
+
risk: "Piped data sent to external server",
|
|
468
|
+
legitimateUses: ["Uploading files to your own API", "CI/CD pipelines"]
|
|
395
469
|
},
|
|
396
470
|
// Reverse copy tools
|
|
397
471
|
{
|
|
398
472
|
name: "scp_outbound",
|
|
399
473
|
pattern: /scp\s+.*[^@]+@[^:]+:/i,
|
|
400
474
|
severity: "high",
|
|
401
|
-
description: "scp to remote host (potential data exfil)"
|
|
475
|
+
description: "scp to remote host (potential data exfil)",
|
|
476
|
+
risk: "Files copied to remote server",
|
|
477
|
+
legitimateUses: ["Deploying to your servers", "Backup operations"]
|
|
402
478
|
},
|
|
403
479
|
{
|
|
404
480
|
name: "rsync_outbound",
|
|
405
481
|
pattern: /rsync\s+.*[^@]+@/i,
|
|
406
482
|
severity: "high",
|
|
407
|
-
description: "rsync to remote host (potential data exfil)"
|
|
483
|
+
description: "rsync to remote host (potential data exfil)",
|
|
484
|
+
risk: "Files synced to remote server",
|
|
485
|
+
legitimateUses: ["Deploying to your servers", "Backup operations"]
|
|
408
486
|
},
|
|
409
487
|
// Backtick command substitution with env vars
|
|
410
488
|
{
|
|
411
489
|
name: "backtick_env_exfil",
|
|
412
490
|
pattern: /curl.*`.*\$[A-Z_]+.*`/i,
|
|
413
491
|
severity: "critical",
|
|
414
|
-
description: "curl with backtick command substitution containing env var"
|
|
492
|
+
description: "curl with backtick command substitution containing env var",
|
|
493
|
+
risk: DATA_EXFIL_RISK,
|
|
494
|
+
legitimateUses: DATA_EXFIL_LEGIT
|
|
415
495
|
},
|
|
416
496
|
// DNS tunneling patterns
|
|
417
497
|
{
|
|
418
498
|
name: "dns_tunnel_dig",
|
|
419
499
|
pattern: /dig\s+.*\$[A-Z_]/i,
|
|
420
500
|
severity: "high",
|
|
421
|
-
description: "DNS query with environment variable (potential DNS tunnel)"
|
|
501
|
+
description: "DNS query with environment variable (potential DNS tunnel)",
|
|
502
|
+
risk: "Data exfiltration via DNS queries - bypasses firewalls",
|
|
503
|
+
legitimateUses: ["Dynamic DNS lookups", "DNS debugging"]
|
|
422
504
|
},
|
|
423
505
|
{
|
|
424
506
|
name: "dns_tunnel_nslookup",
|
|
425
507
|
pattern: /nslookup\s+.*\$[A-Z_]/i,
|
|
426
508
|
severity: "high",
|
|
427
|
-
description: "nslookup with environment variable (potential DNS tunnel)"
|
|
509
|
+
description: "nslookup with environment variable (potential DNS tunnel)",
|
|
510
|
+
risk: "Data exfiltration via DNS queries - bypasses firewalls",
|
|
511
|
+
legitimateUses: ["Dynamic DNS lookups", "DNS debugging"]
|
|
428
512
|
}
|
|
429
513
|
];
|
|
514
|
+
var CRYPTO_RISK = "Uses your CPU/GPU for cryptocurrency mining, slowing system and increasing power costs";
|
|
515
|
+
var CRYPTO_LEGIT = ["Intentional mining on your own hardware", "Mining pool testing"];
|
|
430
516
|
var CRYPTO_MINING_PATTERNS = [
|
|
431
517
|
{
|
|
432
518
|
name: "xmrig",
|
|
433
519
|
pattern: /xmrig/i,
|
|
434
520
|
severity: "critical",
|
|
435
|
-
description: "XMRig cryptocurrency miner"
|
|
521
|
+
description: "XMRig cryptocurrency miner",
|
|
522
|
+
risk: CRYPTO_RISK,
|
|
523
|
+
legitimateUses: CRYPTO_LEGIT
|
|
436
524
|
},
|
|
437
525
|
{
|
|
438
526
|
name: "minerd",
|
|
439
527
|
pattern: /minerd/i,
|
|
440
528
|
severity: "critical",
|
|
441
|
-
description: "Minerd cryptocurrency miner"
|
|
529
|
+
description: "Minerd cryptocurrency miner",
|
|
530
|
+
risk: CRYPTO_RISK,
|
|
531
|
+
legitimateUses: CRYPTO_LEGIT
|
|
442
532
|
},
|
|
443
533
|
{
|
|
444
534
|
name: "cgminer",
|
|
445
535
|
pattern: /cgminer/i,
|
|
446
536
|
severity: "critical",
|
|
447
|
-
description: "CGMiner cryptocurrency miner"
|
|
537
|
+
description: "CGMiner cryptocurrency miner",
|
|
538
|
+
risk: CRYPTO_RISK,
|
|
539
|
+
legitimateUses: CRYPTO_LEGIT
|
|
448
540
|
},
|
|
449
541
|
{
|
|
450
542
|
name: "bfgminer",
|
|
451
543
|
pattern: /bfgminer/i,
|
|
452
544
|
severity: "critical",
|
|
453
|
-
description: "BFGMiner cryptocurrency miner"
|
|
545
|
+
description: "BFGMiner cryptocurrency miner",
|
|
546
|
+
risk: CRYPTO_RISK,
|
|
547
|
+
legitimateUses: CRYPTO_LEGIT
|
|
454
548
|
},
|
|
455
549
|
{
|
|
456
550
|
name: "stratum_protocol",
|
|
457
551
|
pattern: /stratum\+tcp/i,
|
|
458
552
|
severity: "critical",
|
|
459
|
-
description: "Stratum mining protocol"
|
|
553
|
+
description: "Stratum mining protocol",
|
|
554
|
+
risk: CRYPTO_RISK,
|
|
555
|
+
legitimateUses: CRYPTO_LEGIT
|
|
460
556
|
}
|
|
461
557
|
];
|
|
558
|
+
var OBFUSCATED_RISK = "Hidden/encoded commands executed - content cannot be reviewed before running";
|
|
559
|
+
var OBFUSCATED_LEGIT = ["Running encoded payloads in security testing", "Decoding legitimate scripts"];
|
|
462
560
|
var OBFUSCATED_EXEC_PATTERNS = [
|
|
463
561
|
{
|
|
464
562
|
name: "base64_pipe_bash",
|
|
465
563
|
pattern: /\|\s*base64\s+-d\s*\|\s*(ba)?sh/i,
|
|
466
564
|
severity: "critical",
|
|
467
|
-
description: "Base64 decode piped to shell"
|
|
565
|
+
description: "Base64 decode piped to shell",
|
|
566
|
+
risk: OBFUSCATED_RISK,
|
|
567
|
+
legitimateUses: OBFUSCATED_LEGIT
|
|
468
568
|
},
|
|
469
569
|
{
|
|
470
570
|
name: "base64_decode_bash",
|
|
471
571
|
pattern: /base64\s+(-d|--decode)\s+\S+\s*\|\s*(ba)?sh/i,
|
|
472
572
|
severity: "critical",
|
|
473
|
-
description: "Base64 decode from file piped to shell"
|
|
573
|
+
description: "Base64 decode from file piped to shell",
|
|
574
|
+
risk: OBFUSCATED_RISK,
|
|
575
|
+
legitimateUses: OBFUSCATED_LEGIT
|
|
474
576
|
},
|
|
475
577
|
{
|
|
476
578
|
name: "eval_base64_decode",
|
|
477
579
|
pattern: /eval\s*\(\s*base64_decode/i,
|
|
478
580
|
severity: "critical",
|
|
479
|
-
description: "PHP-style eval with base64 decode"
|
|
581
|
+
description: "PHP-style eval with base64 decode",
|
|
582
|
+
risk: OBFUSCATED_RISK,
|
|
583
|
+
legitimateUses: OBFUSCATED_LEGIT
|
|
480
584
|
},
|
|
481
585
|
// Bypass techniques
|
|
482
586
|
{
|
|
483
587
|
name: "eval_curl",
|
|
484
588
|
pattern: /eval\s+.*\$\(.*curl/i,
|
|
485
589
|
severity: "critical",
|
|
486
|
-
description: "eval with curl command substitution"
|
|
590
|
+
description: "eval with curl command substitution",
|
|
591
|
+
risk: "Remote code downloaded and executed immediately",
|
|
592
|
+
legitimateUses: ["Running installer scripts you trust"]
|
|
487
593
|
},
|
|
488
594
|
{
|
|
489
595
|
name: "eval_wget",
|
|
490
596
|
pattern: /eval\s+.*\$\(.*wget/i,
|
|
491
597
|
severity: "critical",
|
|
492
|
-
description: "eval with wget command substitution"
|
|
598
|
+
description: "eval with wget command substitution",
|
|
599
|
+
risk: "Remote code downloaded and executed immediately",
|
|
600
|
+
legitimateUses: ["Running installer scripts you trust"]
|
|
493
601
|
},
|
|
494
602
|
{
|
|
495
603
|
name: "bash_herestring_curl",
|
|
496
604
|
pattern: /bash\s+<<<\s*.*\$\(.*curl/i,
|
|
497
605
|
severity: "critical",
|
|
498
|
-
description: "bash here-string with curl"
|
|
606
|
+
description: "bash here-string with curl",
|
|
607
|
+
risk: "Remote code downloaded and executed via here-string",
|
|
608
|
+
legitimateUses: ["Running installer scripts you trust"]
|
|
499
609
|
},
|
|
500
610
|
{
|
|
501
611
|
name: "bash_process_sub",
|
|
502
612
|
pattern: /bash\s+<\(.*curl/i,
|
|
503
613
|
severity: "critical",
|
|
504
|
-
description: "bash process substitution with curl"
|
|
614
|
+
description: "bash process substitution with curl",
|
|
615
|
+
risk: "Remote code downloaded and executed via process substitution",
|
|
616
|
+
legitimateUses: ["Running installer scripts you trust"]
|
|
505
617
|
},
|
|
506
618
|
{
|
|
507
619
|
name: "bash_process_sub_wget",
|
|
508
620
|
pattern: /bash\s+<\(.*wget/i,
|
|
509
621
|
severity: "critical",
|
|
510
|
-
description: "bash process substitution with wget"
|
|
622
|
+
description: "bash process substitution with wget",
|
|
623
|
+
risk: "Remote code downloaded and executed via process substitution",
|
|
624
|
+
legitimateUses: ["Running installer scripts you trust"]
|
|
511
625
|
}
|
|
512
626
|
];
|
|
513
627
|
var DESTRUCTIVE_PATTERNS = [
|
|
@@ -515,61 +629,81 @@ var DESTRUCTIVE_PATTERNS = [
|
|
|
515
629
|
name: "rm_rf_root",
|
|
516
630
|
pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)*-[a-zA-Z]*r[a-zA-Z]*.*\s+\/(\s|$|;|&)/i,
|
|
517
631
|
severity: "critical",
|
|
518
|
-
description: "rm -rf on root directory"
|
|
632
|
+
description: "rm -rf on root directory",
|
|
633
|
+
risk: "Deletes entire filesystem - complete data loss, unbootable system",
|
|
634
|
+
legitimateUses: ["Wiping a system intentionally before reinstall"]
|
|
519
635
|
},
|
|
520
636
|
{
|
|
521
637
|
name: "rm_rf_home",
|
|
522
638
|
pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)*-[a-zA-Z]*r[a-zA-Z]*.*\s+(~|\/home|\$HOME)/i,
|
|
523
639
|
severity: "critical",
|
|
524
|
-
description: "rm -rf on home directory"
|
|
640
|
+
description: "rm -rf on home directory",
|
|
641
|
+
risk: "Deletes all user files - documents, configs, ssh keys, everything",
|
|
642
|
+
legitimateUses: ["Cleaning up a user account before deletion"]
|
|
525
643
|
},
|
|
526
644
|
{
|
|
527
645
|
name: "rm_rf_star",
|
|
528
646
|
pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)*-[a-zA-Z]*r[a-zA-Z]*\s+\*/i,
|
|
529
647
|
severity: "critical",
|
|
530
|
-
description: "rm -rf with wildcard"
|
|
648
|
+
description: "rm -rf with wildcard",
|
|
649
|
+
risk: "Deletes all files in current directory recursively",
|
|
650
|
+
legitimateUses: ["Cleaning build artifacts", "Resetting test environment"]
|
|
531
651
|
},
|
|
532
652
|
{
|
|
533
653
|
name: "mkfs_format",
|
|
534
654
|
pattern: /mkfs(\.[a-z0-9]+)?\s+\/dev\//i,
|
|
535
655
|
severity: "critical",
|
|
536
|
-
description: "mkfs filesystem format on device"
|
|
656
|
+
description: "mkfs filesystem format on device",
|
|
657
|
+
risk: "Formats disk - all data on device will be permanently lost",
|
|
658
|
+
legitimateUses: ["Setting up new disk", "Creating bootable drives"]
|
|
537
659
|
},
|
|
538
660
|
{
|
|
539
661
|
name: "dd_destructive",
|
|
540
662
|
pattern: /dd\s+.*of=\/dev\/[hs]d/i,
|
|
541
663
|
severity: "critical",
|
|
542
|
-
description: "dd write to disk device"
|
|
664
|
+
description: "dd write to disk device",
|
|
665
|
+
risk: "Overwrites disk directly - data loss, potential boot failure",
|
|
666
|
+
legitimateUses: ["Creating bootable USB", "Disk imaging"]
|
|
543
667
|
},
|
|
544
668
|
{
|
|
545
669
|
name: "dd_zero_device",
|
|
546
670
|
pattern: /dd\s+.*if=\/dev\/(zero|urandom).*of=\/dev\//i,
|
|
547
671
|
severity: "critical",
|
|
548
|
-
description: "dd zero/random write to device"
|
|
672
|
+
description: "dd zero/random write to device",
|
|
673
|
+
risk: "Wipes disk with zeros/random data - complete, unrecoverable data loss",
|
|
674
|
+
legitimateUses: ["Secure disk wiping", "Preparing disk for disposal"]
|
|
549
675
|
},
|
|
550
676
|
{
|
|
551
677
|
name: "fork_bomb",
|
|
552
678
|
pattern: /:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;?\s*:/,
|
|
553
679
|
severity: "critical",
|
|
554
|
-
description: "Fork bomb"
|
|
680
|
+
description: "Fork bomb",
|
|
681
|
+
risk: "Creates infinite processes - system freeze, requires hard reboot",
|
|
682
|
+
legitimateUses: ["Testing system limits", "Security demonstrations"]
|
|
555
683
|
},
|
|
556
684
|
{
|
|
557
685
|
name: "fork_bomb_variant",
|
|
558
686
|
pattern: /\w+\(\)\s*\{\s*\w+\s*\|\s*\w+\s*&\s*\}\s*;?\s*\w+/,
|
|
559
687
|
severity: "critical",
|
|
560
|
-
description: "Fork bomb variant"
|
|
688
|
+
description: "Fork bomb variant",
|
|
689
|
+
risk: "Creates infinite processes - system freeze, requires hard reboot",
|
|
690
|
+
legitimateUses: ["Testing system limits", "Security demonstrations"]
|
|
561
691
|
},
|
|
562
692
|
{
|
|
563
693
|
name: "chmod_recursive_777",
|
|
564
694
|
pattern: /chmod\s+(-R|--recursive)\s+777\s+\//i,
|
|
565
695
|
severity: "critical",
|
|
566
|
-
description: "chmod 777 recursive on system directories"
|
|
696
|
+
description: "chmod 777 recursive on system directories",
|
|
697
|
+
risk: "Makes all system files world-writable - severe security vulnerability",
|
|
698
|
+
legitimateUses: ["Almost never legitimate on system directories"]
|
|
567
699
|
},
|
|
568
700
|
{
|
|
569
701
|
name: "chown_recursive_root",
|
|
570
702
|
pattern: /chown\s+(-R|--recursive)\s+.*\s+\/(\s|$)/i,
|
|
571
703
|
severity: "critical",
|
|
572
|
-
description: "chown recursive on root"
|
|
704
|
+
description: "chown recursive on root",
|
|
705
|
+
risk: "Changes ownership of all system files - can break system",
|
|
706
|
+
legitimateUses: ["System recovery operations"]
|
|
573
707
|
}
|
|
574
708
|
];
|
|
575
709
|
var INSTANT_BLOCK_PATTERNS = [
|
|
@@ -612,21 +746,23 @@ var CHECKPOINT_PATTERNS = [
|
|
|
612
746
|
];
|
|
613
747
|
|
|
614
748
|
// src/guard/instant-block.ts
|
|
615
|
-
function
|
|
749
|
+
function checkHighRiskPatterns(command) {
|
|
616
750
|
if (!command || !command.trim()) {
|
|
617
|
-
return {
|
|
751
|
+
return { detected: false };
|
|
618
752
|
}
|
|
619
753
|
for (const pattern of INSTANT_BLOCK_PATTERNS) {
|
|
620
754
|
if (pattern.pattern.test(command)) {
|
|
621
755
|
return {
|
|
622
|
-
|
|
623
|
-
reason: `Blocked: Matches dangerous pattern - ${pattern.description}`,
|
|
756
|
+
detected: true,
|
|
624
757
|
patternName: pattern.name,
|
|
625
|
-
severity: pattern.severity
|
|
758
|
+
severity: pattern.severity,
|
|
759
|
+
description: pattern.description,
|
|
760
|
+
risk: pattern.risk,
|
|
761
|
+
legitimateUses: pattern.legitimateUses
|
|
626
762
|
};
|
|
627
763
|
}
|
|
628
764
|
}
|
|
629
|
-
return {
|
|
765
|
+
return { detected: false };
|
|
630
766
|
}
|
|
631
767
|
|
|
632
768
|
// src/guard/instant-allow.ts
|
|
@@ -906,67 +1042,325 @@ function checkTrustedDomains(command) {
|
|
|
906
1042
|
}
|
|
907
1043
|
|
|
908
1044
|
// src/guard/file-tools.ts
|
|
909
|
-
var
|
|
1045
|
+
var WRITE_SENSITIVE_PATHS = [
|
|
910
1046
|
// SSH - Critical (persistent access)
|
|
911
|
-
{
|
|
912
|
-
|
|
913
|
-
|
|
1047
|
+
{
|
|
1048
|
+
pattern: /^~?\/?\.ssh\//i,
|
|
1049
|
+
description: "SSH directory",
|
|
1050
|
+
severity: "critical",
|
|
1051
|
+
risk: "Attacker can add their key for persistent remote access",
|
|
1052
|
+
legitimateUses: ["Adding new SSH keys", "Configuring SSH"]
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
pattern: /\.ssh\/authorized_keys$/i,
|
|
1056
|
+
description: "SSH authorized_keys",
|
|
1057
|
+
severity: "critical",
|
|
1058
|
+
risk: "Attacker gains persistent SSH access to your machine",
|
|
1059
|
+
legitimateUses: ["Adding authorized keys for remote access"]
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
pattern: /\.ssh\/config$/i,
|
|
1063
|
+
description: "SSH config",
|
|
1064
|
+
severity: "critical",
|
|
1065
|
+
risk: "Can redirect SSH connections to attacker-controlled servers",
|
|
1066
|
+
legitimateUses: ["Configuring SSH hosts and options"]
|
|
1067
|
+
},
|
|
914
1068
|
// Cloud credentials - Critical
|
|
915
|
-
{
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1069
|
+
{
|
|
1070
|
+
pattern: /^~?\/?\.aws\//i,
|
|
1071
|
+
description: "AWS credentials directory",
|
|
1072
|
+
severity: "critical",
|
|
1073
|
+
risk: "Attacker gains access to your AWS account",
|
|
1074
|
+
legitimateUses: ["Configuring AWS CLI", "Setting up AWS profiles"]
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
pattern: /^~?\/?\.azure\//i,
|
|
1078
|
+
description: "Azure credentials directory",
|
|
1079
|
+
severity: "critical",
|
|
1080
|
+
risk: "Attacker gains access to your Azure account",
|
|
1081
|
+
legitimateUses: ["Configuring Azure CLI"]
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
pattern: /^~?\/?\.gcloud\//i,
|
|
1085
|
+
description: "GCloud credentials directory",
|
|
1086
|
+
severity: "critical",
|
|
1087
|
+
risk: "Attacker gains access to your Google Cloud account",
|
|
1088
|
+
legitimateUses: ["Configuring gcloud CLI"]
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
pattern: /^~?\/?\.config\/gcloud\//i,
|
|
1092
|
+
description: "GCloud config directory",
|
|
1093
|
+
severity: "critical",
|
|
1094
|
+
risk: "Attacker gains access to your Google Cloud account",
|
|
1095
|
+
legitimateUses: ["Configuring gcloud CLI"]
|
|
1096
|
+
},
|
|
919
1097
|
// GPG/Crypto - Critical
|
|
920
|
-
{
|
|
1098
|
+
{
|
|
1099
|
+
pattern: /^~?\/?\.gnupg\//i,
|
|
1100
|
+
description: "GPG directory",
|
|
1101
|
+
severity: "critical",
|
|
1102
|
+
risk: "Attacker can sign/encrypt as you or steal your keys",
|
|
1103
|
+
legitimateUses: ["Managing GPG keys", "Configuring GPG"]
|
|
1104
|
+
},
|
|
921
1105
|
// System config - Critical
|
|
922
|
-
{
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1106
|
+
{
|
|
1107
|
+
pattern: /^\/etc\//i,
|
|
1108
|
+
description: "System /etc directory",
|
|
1109
|
+
severity: "critical",
|
|
1110
|
+
risk: "Can modify system configuration, add users, change permissions",
|
|
1111
|
+
legitimateUses: ["System administration", "Server configuration"]
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
pattern: /^\/usr\//i,
|
|
1115
|
+
description: "System /usr directory",
|
|
1116
|
+
severity: "critical",
|
|
1117
|
+
risk: "Can replace system binaries with malicious versions",
|
|
1118
|
+
legitimateUses: ["Installing software", "System administration"]
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
pattern: /^\/bin\//i,
|
|
1122
|
+
description: "System /bin directory",
|
|
1123
|
+
severity: "critical",
|
|
1124
|
+
risk: "Can replace core system commands",
|
|
1125
|
+
legitimateUses: ["System administration"]
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
pattern: /^\/sbin\//i,
|
|
1129
|
+
description: "System /sbin directory",
|
|
1130
|
+
severity: "critical",
|
|
1131
|
+
risk: "Can replace system administration commands",
|
|
1132
|
+
legitimateUses: ["System administration"]
|
|
1133
|
+
},
|
|
926
1134
|
// Shell startup files - High (code execution on shell start)
|
|
927
|
-
{
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1135
|
+
{
|
|
1136
|
+
pattern: /^~?\/?\.bashrc$/i,
|
|
1137
|
+
description: "Bash startup file",
|
|
1138
|
+
severity: "high",
|
|
1139
|
+
risk: "Code runs every time you open a terminal",
|
|
1140
|
+
legitimateUses: ["Adding aliases", "Setting environment variables", "Shell customization"]
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
pattern: /^~?\/?\.bash_profile$/i,
|
|
1144
|
+
description: "Bash profile",
|
|
1145
|
+
severity: "high",
|
|
1146
|
+
risk: "Code runs on login shell startup",
|
|
1147
|
+
legitimateUses: ["Login shell configuration"]
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
pattern: /^~?\/?\.zshrc$/i,
|
|
1151
|
+
description: "Zsh startup file",
|
|
1152
|
+
severity: "high",
|
|
1153
|
+
risk: "Code runs every time you open a terminal",
|
|
1154
|
+
legitimateUses: ["Adding aliases", "Setting environment variables", "Shell customization"]
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
pattern: /^~?\/?\.zprofile$/i,
|
|
1158
|
+
description: "Zsh profile",
|
|
1159
|
+
severity: "high",
|
|
1160
|
+
risk: "Code runs on login shell startup",
|
|
1161
|
+
legitimateUses: ["Login shell configuration"]
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
pattern: /^~?\/?\.profile$/i,
|
|
1165
|
+
description: "Shell profile",
|
|
1166
|
+
severity: "high",
|
|
1167
|
+
risk: "Code runs on shell startup",
|
|
1168
|
+
legitimateUses: ["Shell configuration"]
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
pattern: /^~?\/?\.bash_logout$/i,
|
|
1172
|
+
description: "Bash logout script",
|
|
1173
|
+
severity: "high",
|
|
1174
|
+
risk: "Code runs when you close terminal",
|
|
1175
|
+
legitimateUses: ["Cleanup scripts"]
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
pattern: /^~?\/?\.zlogout$/i,
|
|
1179
|
+
description: "Zsh logout script",
|
|
1180
|
+
severity: "high",
|
|
1181
|
+
risk: "Code runs when you close terminal",
|
|
1182
|
+
legitimateUses: ["Cleanup scripts"]
|
|
1183
|
+
},
|
|
934
1184
|
// Cron - High (scheduled code execution)
|
|
935
|
-
{
|
|
936
|
-
|
|
1185
|
+
{
|
|
1186
|
+
pattern: /crontab/i,
|
|
1187
|
+
description: "Crontab file",
|
|
1188
|
+
severity: "high",
|
|
1189
|
+
risk: "Can schedule malicious code to run periodically",
|
|
1190
|
+
legitimateUses: ["Setting up scheduled tasks", "Automation"]
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
pattern: /^\/var\/spool\/cron\//i,
|
|
1194
|
+
description: "Cron spool directory",
|
|
1195
|
+
severity: "high",
|
|
1196
|
+
risk: "Can schedule malicious code to run periodically",
|
|
1197
|
+
legitimateUses: ["System cron job management"]
|
|
1198
|
+
},
|
|
937
1199
|
// Git hooks - High (code execution on git operations)
|
|
938
|
-
{
|
|
1200
|
+
{
|
|
1201
|
+
pattern: /\.git\/hooks\//i,
|
|
1202
|
+
description: "Git hooks directory",
|
|
1203
|
+
severity: "high",
|
|
1204
|
+
risk: "Code runs automatically on git operations (commit, push, etc.)",
|
|
1205
|
+
legitimateUses: ["Setting up pre-commit hooks", "CI/CD integration", "Code formatting"]
|
|
1206
|
+
},
|
|
939
1207
|
// Package managers config (supply chain risk)
|
|
940
|
-
{
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1208
|
+
{
|
|
1209
|
+
pattern: /^~?\/?\.npmrc$/i,
|
|
1210
|
+
description: "NPM config (may contain tokens)",
|
|
1211
|
+
severity: "high",
|
|
1212
|
+
risk: "Can steal npm tokens or redirect package installs",
|
|
1213
|
+
legitimateUses: ["Configuring npm registry", "Setting up private packages"]
|
|
1214
|
+
},
|
|
1215
|
+
{
|
|
1216
|
+
pattern: /^~?\/?\.pypirc$/i,
|
|
1217
|
+
description: "PyPI config (may contain tokens)",
|
|
1218
|
+
severity: "high",
|
|
1219
|
+
risk: "Can steal PyPI tokens or redirect package installs",
|
|
1220
|
+
legitimateUses: ["Configuring PyPI", "Publishing packages"]
|
|
1221
|
+
},
|
|
1222
|
+
// Claude Code config - High (could modify AI behavior)
|
|
1223
|
+
{
|
|
1224
|
+
pattern: /CLAUDE\.md$/i,
|
|
1225
|
+
description: "Claude instructions file",
|
|
1226
|
+
severity: "high",
|
|
1227
|
+
risk: "Can modify AI behavior and disable security rules",
|
|
1228
|
+
legitimateUses: ["Updating project instructions", "Configuring Claude behavior"]
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
pattern: /^~?\/?\.claude\//i,
|
|
1232
|
+
description: "Claude config directory",
|
|
1233
|
+
severity: "high",
|
|
1234
|
+
risk: "Can modify Claude Code settings",
|
|
1235
|
+
legitimateUses: ["Configuring Claude Code"]
|
|
1236
|
+
}
|
|
945
1237
|
];
|
|
946
|
-
var
|
|
1238
|
+
var READ_SENSITIVE_PATHS = [
|
|
947
1239
|
// Private keys - Critical
|
|
948
|
-
{
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1240
|
+
{
|
|
1241
|
+
pattern: /\.ssh\/id_rsa$/i,
|
|
1242
|
+
description: "SSH private key (RSA)",
|
|
1243
|
+
severity: "critical",
|
|
1244
|
+
risk: "Private key can be used to access all your SSH-protected servers",
|
|
1245
|
+
legitimateUses: ["Backing up keys", "Key migration"]
|
|
1246
|
+
},
|
|
1247
|
+
{
|
|
1248
|
+
pattern: /\.ssh\/id_ed25519$/i,
|
|
1249
|
+
description: "SSH private key (Ed25519)",
|
|
1250
|
+
severity: "critical",
|
|
1251
|
+
risk: "Private key can be used to access all your SSH-protected servers",
|
|
1252
|
+
legitimateUses: ["Backing up keys", "Key migration"]
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
pattern: /\.ssh\/id_ecdsa$/i,
|
|
1256
|
+
description: "SSH private key (ECDSA)",
|
|
1257
|
+
severity: "critical",
|
|
1258
|
+
risk: "Private key can be used to access all your SSH-protected servers",
|
|
1259
|
+
legitimateUses: ["Backing up keys", "Key migration"]
|
|
1260
|
+
},
|
|
1261
|
+
{
|
|
1262
|
+
pattern: /\.ssh\/id_dsa$/i,
|
|
1263
|
+
description: "SSH private key (DSA)",
|
|
1264
|
+
severity: "critical",
|
|
1265
|
+
risk: "Private key can be used to access all your SSH-protected servers",
|
|
1266
|
+
legitimateUses: ["Backing up keys", "Key migration"]
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
pattern: /\.pem$/i,
|
|
1270
|
+
description: "PEM private key",
|
|
1271
|
+
severity: "critical",
|
|
1272
|
+
risk: "Private key file - could grant access to servers or services",
|
|
1273
|
+
legitimateUses: ["Certificate management", "Server configuration"]
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
pattern: /\.key$/i,
|
|
1277
|
+
description: "Private key file",
|
|
1278
|
+
severity: "critical",
|
|
1279
|
+
risk: "Private key file - could grant access to servers or services",
|
|
1280
|
+
legitimateUses: ["Certificate management", "SSL configuration"]
|
|
1281
|
+
},
|
|
954
1282
|
// Cloud credentials - Critical
|
|
955
|
-
{
|
|
956
|
-
|
|
1283
|
+
{
|
|
1284
|
+
pattern: /\.aws\/credentials$/i,
|
|
1285
|
+
description: "AWS credentials",
|
|
1286
|
+
severity: "critical",
|
|
1287
|
+
risk: "Full access to your AWS account - can create resources, access data",
|
|
1288
|
+
legitimateUses: ["Credential rotation", "Backup"]
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
pattern: /\.azure\/credentials$/i,
|
|
1292
|
+
description: "Azure credentials",
|
|
1293
|
+
severity: "critical",
|
|
1294
|
+
risk: "Full access to your Azure account",
|
|
1295
|
+
legitimateUses: ["Credential rotation", "Backup"]
|
|
1296
|
+
},
|
|
957
1297
|
// Environment files - High
|
|
958
|
-
{
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1298
|
+
{
|
|
1299
|
+
pattern: /\.env$/i,
|
|
1300
|
+
description: "Environment file",
|
|
1301
|
+
severity: "high",
|
|
1302
|
+
risk: "Contains API keys, database passwords, and other secrets",
|
|
1303
|
+
legitimateUses: ["Debugging", "Environment setup", "Configuration review"]
|
|
1304
|
+
},
|
|
1305
|
+
{
|
|
1306
|
+
pattern: /\.env\.local$/i,
|
|
1307
|
+
description: "Local environment file",
|
|
1308
|
+
severity: "high",
|
|
1309
|
+
risk: "Contains local development secrets",
|
|
1310
|
+
legitimateUses: ["Debugging", "Local development"]
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
pattern: /\.env\.production$/i,
|
|
1314
|
+
description: "Production environment file",
|
|
1315
|
+
severity: "high",
|
|
1316
|
+
risk: "Contains production secrets - highest value target",
|
|
1317
|
+
legitimateUses: ["Deployment configuration", "Debugging production issues"]
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
pattern: /\.env\.development$/i,
|
|
1321
|
+
description: "Development environment file",
|
|
1322
|
+
severity: "high",
|
|
1323
|
+
risk: "Contains development secrets",
|
|
1324
|
+
legitimateUses: ["Development setup"]
|
|
1325
|
+
},
|
|
962
1326
|
// Password/credential files - Critical
|
|
963
|
-
{
|
|
964
|
-
|
|
1327
|
+
{
|
|
1328
|
+
pattern: /^\/etc\/shadow$/i,
|
|
1329
|
+
description: "System shadow file",
|
|
1330
|
+
severity: "critical",
|
|
1331
|
+
risk: "Contains hashed passwords for all system users",
|
|
1332
|
+
legitimateUses: ["System administration", "Security auditing"]
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
pattern: /^\/etc\/passwd$/i,
|
|
1336
|
+
description: "System passwd file",
|
|
1337
|
+
severity: "high",
|
|
1338
|
+
risk: "Contains user account information",
|
|
1339
|
+
legitimateUses: ["System administration", "User management"]
|
|
1340
|
+
},
|
|
965
1341
|
// Browser/app credentials
|
|
966
|
-
{
|
|
967
|
-
|
|
1342
|
+
{
|
|
1343
|
+
pattern: /\.netrc$/i,
|
|
1344
|
+
description: "Netrc credentials",
|
|
1345
|
+
severity: "critical",
|
|
1346
|
+
risk: "Contains plaintext passwords for FTP/HTTP authentication",
|
|
1347
|
+
legitimateUses: ["Credential management"]
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
pattern: /\.docker\/config\.json$/i,
|
|
1351
|
+
description: "Docker config (may contain tokens)",
|
|
1352
|
+
severity: "high",
|
|
1353
|
+
risk: "May contain registry authentication tokens",
|
|
1354
|
+
legitimateUses: ["Docker configuration", "Registry setup"]
|
|
1355
|
+
},
|
|
968
1356
|
// Keychain/secret stores
|
|
969
|
-
{
|
|
1357
|
+
{
|
|
1358
|
+
pattern: /\.gnupg\/private-keys/i,
|
|
1359
|
+
description: "GPG private keys",
|
|
1360
|
+
severity: "critical",
|
|
1361
|
+
risk: "Can decrypt messages and sign as you",
|
|
1362
|
+
legitimateUses: ["Key backup", "Key migration"]
|
|
1363
|
+
}
|
|
970
1364
|
];
|
|
971
1365
|
function normalizePath(filePath) {
|
|
972
1366
|
let normalized = filePath.replace(/\$HOME/g, "~").replace(/\$\{HOME\}/g, "~");
|
|
@@ -976,22 +1370,26 @@ function normalizePath(filePath) {
|
|
|
976
1370
|
function checkFilePath(filePath, action) {
|
|
977
1371
|
const normalized = normalizePath(filePath);
|
|
978
1372
|
if (action === "read") {
|
|
979
|
-
for (const { pattern, description, severity } of
|
|
1373
|
+
for (const { pattern, description, severity, risk, legitimateUses } of READ_SENSITIVE_PATHS) {
|
|
980
1374
|
if (pattern.test(normalized)) {
|
|
981
1375
|
return {
|
|
982
1376
|
blocked: true,
|
|
983
|
-
reason: `
|
|
984
|
-
severity
|
|
1377
|
+
reason: `Reading ${description} (${normalized})`,
|
|
1378
|
+
severity,
|
|
1379
|
+
risk,
|
|
1380
|
+
legitimateUses
|
|
985
1381
|
};
|
|
986
1382
|
}
|
|
987
1383
|
}
|
|
988
1384
|
} else {
|
|
989
|
-
for (const { pattern, description, severity } of
|
|
1385
|
+
for (const { pattern, description, severity, risk, legitimateUses } of WRITE_SENSITIVE_PATHS) {
|
|
990
1386
|
if (pattern.test(normalized)) {
|
|
991
1387
|
return {
|
|
992
1388
|
blocked: true,
|
|
993
|
-
reason:
|
|
994
|
-
severity
|
|
1389
|
+
reason: `${action === "write" ? "Writing to" : "Editing"} ${description} (${normalized})`,
|
|
1390
|
+
severity,
|
|
1391
|
+
risk,
|
|
1392
|
+
legitimateUses
|
|
995
1393
|
};
|
|
996
1394
|
}
|
|
997
1395
|
}
|
|
@@ -1128,7 +1526,18 @@ BLOCK - Obviously dangerous:
|
|
|
1128
1526
|
Respond with ONLY this JSON structure:
|
|
1129
1527
|
{"classification": "SELF_HANDLE" | "ESCALATE" | "BLOCK", "reason": "brief explanation", "risk_indicators": ["list", "of", "concerns"]}
|
|
1130
1528
|
</response_format>`;
|
|
1529
|
+
var FORCE_ESCALATE_TYPES = [
|
|
1530
|
+
"package_install"
|
|
1531
|
+
// Supply chain attacks via postinstall scripts
|
|
1532
|
+
];
|
|
1131
1533
|
async function triageWithHaiku(client, checkpoint) {
|
|
1534
|
+
if (FORCE_ESCALATE_TYPES.includes(checkpoint.type)) {
|
|
1535
|
+
return {
|
|
1536
|
+
classification: "ESCALATE",
|
|
1537
|
+
reason: `Package installation requires Sonnet review (supply chain risk)`,
|
|
1538
|
+
riskIndicators: ["force_escalate_type", checkpoint.type]
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1132
1541
|
const sanitizedCommand = sanitizeForPrompt(checkpoint.command);
|
|
1133
1542
|
const userPrompt = TRIAGE_USER_PROMPT.replace("{command}", escapeXml(sanitizedCommand)).replace("{checkpoint_type}", escapeXml(checkpoint.type)).replace("{context}", escapeXml(checkpoint.description));
|
|
1134
1543
|
try {
|
|
@@ -1224,6 +1633,15 @@ var REVIEW_USER_PROMPT = `<task>Perform security review of this operation</task>
|
|
|
1224
1633
|
1. Intent Analysis: What is this command trying to accomplish?
|
|
1225
1634
|
2. Risk Assessment: What could go wrong?
|
|
1226
1635
|
3. Mitigation: Are there safer alternatives?
|
|
1636
|
+
4. Secondary Downloads: Does this script/command download and execute additional code?
|
|
1637
|
+
- Look for: curl|wget inside scripts, eval(), bash -c "$(curl ...)", exec()
|
|
1638
|
+
- Check for embedded download URLs that will fetch more code
|
|
1639
|
+
5. Privilege Escalation Flow: Is this part of a dangerous pattern?
|
|
1640
|
+
- download \u2192 chmod +x \u2192 execute \u2192 sudo sequence
|
|
1641
|
+
- Commands requesting elevated permissions after downloading
|
|
1642
|
+
6. Dynamic Execution: Does this use dangerous dynamic execution?
|
|
1643
|
+
- eval, exec, or command substitution with external input
|
|
1644
|
+
- Code that builds and executes strings dynamically
|
|
1227
1645
|
</analysis_required>
|
|
1228
1646
|
|
|
1229
1647
|
<verdict_rules>
|
|
@@ -1231,11 +1649,16 @@ ALLOW - Safe to proceed autonomously:
|
|
|
1231
1649
|
- Legitimate development operation
|
|
1232
1650
|
- No significant risk to system or data
|
|
1233
1651
|
- Source is verifiable and trusted
|
|
1652
|
+
- No secondary downloads or dynamic execution patterns
|
|
1234
1653
|
|
|
1235
|
-
ASK_USER - Need human approval:
|
|
1654
|
+
ASK_USER - Need human approval (choose this if ANY risky pattern detected):
|
|
1236
1655
|
- Operation has potential risks but may be legitimate
|
|
1237
1656
|
- User should understand what will happen
|
|
1238
1657
|
- Provide clear explanation of risks
|
|
1658
|
+
- Contains secondary downloads (curl|wget inside script content)
|
|
1659
|
+
- Part of privilege escalation flow (download + execute + sudo)
|
|
1660
|
+
- Uses dynamic execution (eval, exec with external input)
|
|
1661
|
+
- Downloads content that will be executed later
|
|
1239
1662
|
|
|
1240
1663
|
BLOCK - Do not allow:
|
|
1241
1664
|
- Clear security risk
|
|
@@ -1332,10 +1755,18 @@ async function processPermissionRequest(input, anthropicClient) {
|
|
|
1332
1755
|
if (input.tool_name === "Write" || input.tool_name === "Edit" || input.tool_name === "Read") {
|
|
1333
1756
|
const fileCheck = checkFileTool(input.tool_name, input.tool_input);
|
|
1334
1757
|
if (fileCheck.blocked) {
|
|
1758
|
+
const severityLabel = fileCheck.severity === "critical" ? "SENSITIVE FILE" : "CAUTION";
|
|
1759
|
+
const legitimateUsesText = fileCheck.legitimateUses?.length ? `
|
|
1760
|
+
Common uses: ${fileCheck.legitimateUses.join(", ")}` : "";
|
|
1335
1761
|
return {
|
|
1336
|
-
decision: "
|
|
1337
|
-
reason: fileCheck.reason
|
|
1338
|
-
source: "
|
|
1762
|
+
decision: "needs-review",
|
|
1763
|
+
reason: `[${severityLabel}] ${fileCheck.reason}`,
|
|
1764
|
+
source: "high-risk",
|
|
1765
|
+
userMessage: `[${severityLabel}] ${fileCheck.reason}
|
|
1766
|
+
|
|
1767
|
+
Potential risk: ${fileCheck.risk}${legitimateUsesText}
|
|
1768
|
+
|
|
1769
|
+
Only proceed if you know what you're doing.`
|
|
1339
1770
|
};
|
|
1340
1771
|
}
|
|
1341
1772
|
return {
|
|
@@ -1360,12 +1791,20 @@ async function processPermissionRequest(input, anthropicClient) {
|
|
|
1360
1791
|
source: "instant-allow"
|
|
1361
1792
|
};
|
|
1362
1793
|
}
|
|
1363
|
-
const
|
|
1364
|
-
if (
|
|
1794
|
+
const highRisk = checkHighRiskPatterns(command);
|
|
1795
|
+
if (highRisk.detected) {
|
|
1796
|
+
const severityLabel = highRisk.severity === "critical" ? "HIGH RISK" : "CAUTION";
|
|
1797
|
+
const legitimateUsesText = highRisk.legitimateUses?.length ? `
|
|
1798
|
+
Common uses: ${highRisk.legitimateUses.join(", ")}` : "";
|
|
1365
1799
|
return {
|
|
1366
|
-
decision: "
|
|
1367
|
-
reason:
|
|
1368
|
-
source: "
|
|
1800
|
+
decision: "needs-review",
|
|
1801
|
+
reason: `[${severityLabel}] ${highRisk.description}`,
|
|
1802
|
+
source: "high-risk",
|
|
1803
|
+
userMessage: `[${severityLabel}] ${highRisk.description}
|
|
1804
|
+
|
|
1805
|
+
Potential risk: ${highRisk.risk}${legitimateUsesText}
|
|
1806
|
+
|
|
1807
|
+
Only proceed if you know what you're doing.`
|
|
1369
1808
|
};
|
|
1370
1809
|
}
|
|
1371
1810
|
const checkpoint = detectCheckpoint(command);
|