agent-recon 1.0.1

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.
Files changed (44) hide show
  1. package/.claude/hooks/send-event-wsl.py +339 -0
  2. package/.claude/hooks/send-event.py +334 -0
  3. package/CHANGELOG.md +66 -0
  4. package/CONTRIBUTING.md +70 -0
  5. package/EULA.md +223 -0
  6. package/INSTALL.md +193 -0
  7. package/LICENSE +287 -0
  8. package/LICENSE-COMMERCIAL +241 -0
  9. package/PRIVACY.md +115 -0
  10. package/README.md +182 -0
  11. package/SECURITY.md +63 -0
  12. package/TERMS.md +233 -0
  13. package/install-service.ps1 +302 -0
  14. package/installer/cli.js +177 -0
  15. package/installer/detect.js +355 -0
  16. package/installer/install.js +195 -0
  17. package/installer/manifest.js +140 -0
  18. package/installer/package.json +12 -0
  19. package/installer/steps/api-keys.js +59 -0
  20. package/installer/steps/directory.js +41 -0
  21. package/installer/steps/env-report.js +48 -0
  22. package/installer/steps/hooks.js +149 -0
  23. package/installer/steps/service.js +159 -0
  24. package/installer/steps/tls.js +104 -0
  25. package/installer/steps/verify.js +117 -0
  26. package/installer/steps/welcome.js +46 -0
  27. package/installer/ui.js +133 -0
  28. package/installer/uninstall.js +233 -0
  29. package/installer/upgrade.js +289 -0
  30. package/package.json +58 -0
  31. package/public/index.html +13953 -0
  32. package/server/fixtures/allowlist-profiles.json +185 -0
  33. package/server/package.json +34 -0
  34. package/server/platform.js +270 -0
  35. package/server/rules/gitleaks.toml +3214 -0
  36. package/server/rules/security.yara +579 -0
  37. package/server/start.js +178 -0
  38. package/service/agent-recon.service +30 -0
  39. package/service/com.agent-recon.server.plist +56 -0
  40. package/setup-linux.sh +259 -0
  41. package/setup-macos.sh +264 -0
  42. package/setup-wsl.sh +248 -0
  43. package/setup.ps1 +171 -0
  44. package/start-agent-recon.bat +4 -0
@@ -0,0 +1,579 @@
1
+ /*
2
+ * security.yara — Agent Recon server-side security classification rules.
3
+ *
4
+ * These rules mirror the _SR regex patterns from security-llm.js so that
5
+ * server-side events receive the same classification as browser-side events.
6
+ *
7
+ * Meta fields carried by every rule:
8
+ * sec_cat — maps to secCat in the classification result
9
+ * sec_subcat — maps to secSubcat
10
+ * risk_level — "critical" | "high" | "medium" | "low"
11
+ *
12
+ * IMPORTANT: boolean meta values come back from @litko/yara-x as the string
13
+ * "unknown". All meta values here are strings.
14
+ *
15
+ * Priority order within each group (enforced by yara-scanner.js):
16
+ *
17
+ * Bash: bash_inject_code > bash_inject_pipe > bash_secret_any >
18
+ * bash_data_exfil > bash_exec_priv > bash_auth_tooling >
19
+ * bash_net_ssh_conn > bash_net_call > bash_file_sensitivepath
20
+ *
21
+ * Write: write_file_sensitivepath > write_secret_credwrite
22
+ * Read: read_file_sensitivepath
23
+ * Prompt: prompt_secret_promptsecret > prompt_inject_promptinject
24
+ */
25
+
26
+ // ── Bash / command-string rules ───────────────────────────────────────────────
27
+
28
+ rule bash_inject_code
29
+ {
30
+ meta:
31
+ sec_cat = "inject"
32
+ sec_subcat = "code-injection"
33
+ risk_level = "critical"
34
+ description = "Interpreter invoked with inline code string (python -c, node -e, etc.)"
35
+
36
+ strings:
37
+ // python3? -c followed by a quote
38
+ $py_c = /python3?\s+-c\s+["'`]/ nocase ascii
39
+ // node -e followed by a quote
40
+ $node_e = /node\s+-e\s+["'`]/ nocase ascii
41
+ // perl -e followed by a quote
42
+ $perl_e = /perl\s+-e\s+["'`]/ nocase ascii
43
+ // ruby -e followed by a quote
44
+ $ruby_e = /ruby\s+-e\s+["'`]/ nocase ascii
45
+ // exec( followed by a quote
46
+ $exec_q = /\bexec\s*\(\s*["']/ nocase ascii
47
+
48
+ condition:
49
+ any of them
50
+ }
51
+
52
+ rule bash_inject_pipe
53
+ {
54
+ meta:
55
+ sec_cat = "inject"
56
+ sec_subcat = "pipe-injection"
57
+ risk_level = "high"
58
+ description = "Pipe to shell or command substitution subshell"
59
+
60
+ strings:
61
+ // | sh or | bash
62
+ $pipe_sh = /\|\s*(?:ba)?sh\b/ nocase ascii
63
+ // $( ... ) with at least 5 chars inside
64
+ $cmd_sub = /\$\([^)]{5,}\)/ ascii
65
+
66
+ condition:
67
+ any of them
68
+ }
69
+
70
+ rule bash_secret_any
71
+ {
72
+ meta:
73
+ sec_cat = "secret"
74
+ sec_subcat = "credential-ref"
75
+ risk_level = "high"
76
+ description = "Reference to a secret or credential variable/assignment"
77
+
78
+ strings:
79
+ // ${API_KEY} or $API_KEY variants (case-insensitive variable names)
80
+ $var_api_key = /\$\{?API_KEY\}?/ nocase ascii
81
+ $var_secret = /\$\{?SECRET\}?/ nocase ascii
82
+ $var_token = /\$\{?TOKEN\}?/ nocase ascii
83
+ $var_password = /\$\{?PASSWORD\}?/ nocase ascii
84
+ $var_passwd = /\$\{?PASSWD\}?/ nocase ascii
85
+ $var_access_key = /\$\{?ACCESS_KEY\}?/ nocase ascii
86
+ $var_private_key = /\$\{?PRIVATE_KEY\}?/ nocase ascii
87
+ $var_client_secret = /\$\{?CLIENT_SECRET\}?/ nocase ascii
88
+ $var_auth_token = /\$\{?AUTH_TOKEN\}?/ nocase ascii
89
+ $var_github_token = /\$\{?GITHUB_TOKEN\}?/ nocase ascii
90
+ $var_openai_key = /\$\{?OPENAI_API_KEY\}?/ nocase ascii
91
+ $var_anthropic_key = /\$\{?ANTHROPIC_API_KEY\}?/ nocase ascii
92
+ // bare assignment forms: API_KEY=, SECRET=, TOKEN=
93
+ $assign_api_key = /\bAPI_KEY\s*=/ ascii
94
+ $assign_secret = /\bSECRET\s*=/ ascii
95
+ $assign_token = /\bTOKEN\s*=/ ascii
96
+
97
+ condition:
98
+ any of them
99
+ }
100
+
101
+ rule bash_data_exfil
102
+ {
103
+ meta:
104
+ sec_cat = "data"
105
+ sec_subcat = "exfiltration"
106
+ risk_level = "high"
107
+ description = "Data exfiltration pattern (dd, base64 encode/decode, archive of home, curl/wget POST)"
108
+
109
+ strings:
110
+ $dd_if = /\bdd\s+if=/ nocase ascii
111
+ $base64_de = /\bbase64\s+-[de]\b/ nocase ascii
112
+ $tar_home = /\btar\s+[cC].*\/home\b/ nocase ascii
113
+ $zip_home = /\bzip\s.*\/home\b/ nocase ascii
114
+ $curl_post = /\bcurl\s+[^|]*\s+-d\s/ nocase ascii
115
+ $wget_post = /\bwget\s+.*--post/ nocase ascii
116
+
117
+ condition:
118
+ any of them
119
+ }
120
+
121
+ rule bash_exec_priv
122
+ {
123
+ meta:
124
+ sec_cat = "exec"
125
+ sec_subcat = "priv-escalation"
126
+ risk_level = "high"
127
+ description = "Privilege escalation command (sudo, chmod permissive, chown root, setuid/setcap)"
128
+
129
+ strings:
130
+ $sudo = /\bsudo\b/ nocase ascii
131
+ $su_dash = /\bsu\s+-/ nocase ascii
132
+ // chmod with any digit combination containing 2,3,6,7 in owner/group/other
133
+ $chmod_perm = /\bchmod\s+[0-7]*[2367][0-9]{0,2}\b/ ascii
134
+ $chown_root = /\bchown\s+root/ nocase ascii
135
+ $setuid = /\bsetuid\b/ nocase ascii
136
+ $setcap = /\bsetcap\b/ nocase ascii
137
+ $visudo = /\bvisudo\b/ nocase ascii
138
+ $pkexec = /\bpkexec\b/ nocase ascii
139
+ $doas = /\bdoas\b/ nocase ascii
140
+ $newgrp = /\bnewgrp\b/ nocase ascii
141
+
142
+ condition:
143
+ any of them
144
+ }
145
+
146
+ rule bash_auth_tooling
147
+ {
148
+ meta:
149
+ sec_cat = "auth"
150
+ sec_subcat = "auth-tooling"
151
+ risk_level = "medium"
152
+ description = "Authentication or key management tooling (ssh-keygen, gpg, passwd, openssl genrsa, etc.)"
153
+
154
+ strings:
155
+ $ssh_keygen = /\bssh-keygen\b/ nocase ascii
156
+ $ssh_agent = /\bssh-agent\b/ nocase ascii
157
+ $gpg = /\bgpg\b/ nocase ascii
158
+ $gpg2 = /\bgpg2\b/ nocase ascii
159
+ // passwd omitted: without lookbehind it would match /etc/passwd paths, causing
160
+ // false positives. YARA-X does not support look-around assertions.
161
+ $useradd = /\buseradd\b/ nocase ascii
162
+ $usermod = /\busermod\b/ nocase ascii
163
+ $userdel = /\buserdel\b/ nocase ascii
164
+ $openssl_genrsa = /\bopenssl\s+genrsa/ nocase ascii
165
+ $openssl_req = /\bopenssl\s+req\b/ nocase ascii
166
+ $age_tool = /\bage\b/ nocase ascii
167
+ $keychain = /\bkeychain\b/ nocase ascii
168
+
169
+ condition:
170
+ any of them
171
+ }
172
+
173
+ rule bash_net_ssh_conn
174
+ {
175
+ meta:
176
+ sec_cat = "net"
177
+ sec_subcat = "ssh-connection"
178
+ risk_level = "medium"
179
+ description = "SSH connection to a remote host (user@host pattern)"
180
+
181
+ strings:
182
+ // ssh followed by optional flags then user@host
183
+ $ssh_conn = /\bssh\s+(-[A-Za-z]+\s+)*[a-zA-Z0-9_.-]+@/ ascii
184
+
185
+ condition:
186
+ any of them
187
+ }
188
+
189
+ rule bash_net_call
190
+ {
191
+ meta:
192
+ sec_cat = "net"
193
+ sec_subcat = "network-call"
194
+ risk_level = "low"
195
+ description = "Network utility invocation (curl, wget, nc, scp, etc.)"
196
+
197
+ strings:
198
+ // Note: ssh is intentionally omitted here — user@host connections are
199
+ // caught by bash_net_ssh_conn (higher priority) and key management by
200
+ // bash_auth_tooling. Lookahead exclusions unsupported in YARA-X.
201
+ $curl = /\bcurl\b/ nocase ascii
202
+ $wget = /\bwget\b/ nocase ascii
203
+ $scp = /\bscp\b/ nocase ascii
204
+ $sftp = /\bsftp\b/ nocase ascii
205
+ $nc = /\bnc\b/ nocase ascii
206
+ $ncat = /\bncat\b/ nocase ascii
207
+ $socat = /\bsocat\b/ nocase ascii
208
+ $telnet = /\btelnet\b/ nocase ascii
209
+ $nmap = /\bnmap\b/ nocase ascii
210
+ $rsync = /\brsync\b/ nocase ascii
211
+ $ftp = /\bftp\b/ nocase ascii
212
+
213
+ condition:
214
+ any of them
215
+ }
216
+
217
+ rule bash_file_sensitivepath
218
+ {
219
+ meta:
220
+ sec_cat = "file"
221
+ sec_subcat = "sensitive-path"
222
+ risk_level = "medium"
223
+ description = "Reference to a sensitive filesystem path (SSH keys, AWS creds, /etc/shadow, etc.)"
224
+
225
+ strings:
226
+ $ssh_dir = /\/\.ssh\b/ nocase ascii
227
+ $aws_dir = /\/\.aws\b/ nocase ascii
228
+ $gnupg_dir = /\/\.gnupg\b/ nocase ascii
229
+ $netrc = /\/\.netrc\b/ nocase ascii
230
+ $docker_dir = /\/\.docker\b/ nocase ascii
231
+ $etc_passwd = /\/etc\/passwd\b/ nocase ascii
232
+ $etc_shadow = /\/etc\/shadow\b/ nocase ascii
233
+ $etc_sudoers = /\/etc\/sudoers\b/ nocase ascii
234
+ $etc_cron = /\/etc\/cron\b/ nocase ascii
235
+ $etc_ssh = /\/etc\/ssh\b/ nocase ascii
236
+ $etc_hosts = /\/etc\/hosts\b/ nocase ascii
237
+ $credential = /credential/ nocase ascii
238
+ $dotkey = /\.key$/ nocase ascii
239
+ $dotpem = /\.pem$/ nocase ascii
240
+ $dotenv_ext = /\.env$/ nocase ascii
241
+ $dotenv_word = /\.env\b/ nocase ascii
242
+ $id_rsa = /id_rsa/ nocase ascii
243
+ $auth_keys = /authorized_keys/ nocase ascii
244
+ $dottoken = /\.token\b/ nocase ascii
245
+
246
+ condition:
247
+ any of them
248
+ }
249
+
250
+ // ── Write path rules ──────────────────────────────────────────────────────────
251
+
252
+ rule write_file_sensitivepath
253
+ {
254
+ meta:
255
+ sec_cat = "file"
256
+ sec_subcat = "sensitive-write"
257
+ risk_level = "high"
258
+ description = "Write to a sensitive file path"
259
+
260
+ strings:
261
+ $ssh_dir = /\/\.ssh\b/ nocase ascii
262
+ $aws_dir = /\/\.aws\b/ nocase ascii
263
+ $gnupg_dir = /\/\.gnupg\b/ nocase ascii
264
+ $netrc = /\/\.netrc\b/ nocase ascii
265
+ $docker_dir = /\/\.docker\b/ nocase ascii
266
+ $etc_passwd = /\/etc\/passwd\b/ nocase ascii
267
+ $etc_shadow = /\/etc\/shadow\b/ nocase ascii
268
+ $etc_sudoers = /\/etc\/sudoers\b/ nocase ascii
269
+ $etc_cron = /\/etc\/cron\b/ nocase ascii
270
+ $etc_ssh = /\/etc\/ssh\b/ nocase ascii
271
+ $etc_hosts = /\/etc\/hosts\b/ nocase ascii
272
+ $credential = /credential/ nocase ascii
273
+ $dotkey = /\.key$/ nocase ascii
274
+ $dotpem = /\.pem$/ nocase ascii
275
+ $dotenv_ext = /\.env$/ nocase ascii
276
+ $dotenv_word = /\.env\b/ nocase ascii
277
+ $id_rsa = /id_rsa/ nocase ascii
278
+ $auth_keys = /authorized_keys/ nocase ascii
279
+ $dottoken = /\.token\b/ nocase ascii
280
+
281
+ condition:
282
+ any of them
283
+ }
284
+
285
+ rule write_secret_credwrite
286
+ {
287
+ meta:
288
+ sec_cat = "secret"
289
+ sec_subcat = "credential-write"
290
+ risk_level = "high"
291
+ description = "Content being written contains a credential or secret reference"
292
+
293
+ strings:
294
+ $var_api_key = /\$\{?API_KEY\}?/ nocase ascii
295
+ $var_secret = /\$\{?SECRET\}?/ nocase ascii
296
+ $var_token = /\$\{?TOKEN\}?/ nocase ascii
297
+ $var_password = /\$\{?PASSWORD\}?/ nocase ascii
298
+ $var_passwd = /\$\{?PASSWD\}?/ nocase ascii
299
+ $var_access_key = /\$\{?ACCESS_KEY\}?/ nocase ascii
300
+ $var_private_key = /\$\{?PRIVATE_KEY\}?/ nocase ascii
301
+ $var_client_secret = /\$\{?CLIENT_SECRET\}?/ nocase ascii
302
+ $var_auth_token = /\$\{?AUTH_TOKEN\}?/ nocase ascii
303
+ $var_github_token = /\$\{?GITHUB_TOKEN\}?/ nocase ascii
304
+ $var_openai_key = /\$\{?OPENAI_API_KEY\}?/ nocase ascii
305
+ $var_anthropic_key = /\$\{?ANTHROPIC_API_KEY\}?/ nocase ascii
306
+ $assign_api_key = /\bAPI_KEY\s*=/ ascii
307
+ $assign_secret = /\bSECRET\s*=/ ascii
308
+ $assign_token = /\bTOKEN\s*=/ ascii
309
+
310
+ condition:
311
+ any of them
312
+ }
313
+
314
+ // ── Read / Glob / Grep path rules ─────────────────────────────────────────────
315
+
316
+ rule read_file_sensitivepath
317
+ {
318
+ meta:
319
+ sec_cat = "file"
320
+ sec_subcat = "sensitive-read"
321
+ risk_level = "medium"
322
+ description = "Read/Glob/Grep targeting a sensitive file path"
323
+
324
+ strings:
325
+ $ssh_dir = /\/\.ssh\b/ nocase ascii
326
+ $aws_dir = /\/\.aws\b/ nocase ascii
327
+ $gnupg_dir = /\/\.gnupg\b/ nocase ascii
328
+ $netrc = /\/\.netrc\b/ nocase ascii
329
+ $docker_dir = /\/\.docker\b/ nocase ascii
330
+ $etc_passwd = /\/etc\/passwd\b/ nocase ascii
331
+ $etc_shadow = /\/etc\/shadow\b/ nocase ascii
332
+ $etc_sudoers = /\/etc\/sudoers\b/ nocase ascii
333
+ $etc_cron = /\/etc\/cron\b/ nocase ascii
334
+ $etc_ssh = /\/etc\/ssh\b/ nocase ascii
335
+ $etc_hosts = /\/etc\/hosts\b/ nocase ascii
336
+ $credential = /credential/ nocase ascii
337
+ $dotkey = /\.key$/ nocase ascii
338
+ $dotpem = /\.pem$/ nocase ascii
339
+ $dotenv_ext = /\.env$/ nocase ascii
340
+ $dotenv_word = /\.env\b/ nocase ascii
341
+ $id_rsa = /id_rsa/ nocase ascii
342
+ $auth_keys = /authorized_keys/ nocase ascii
343
+ $dottoken = /\.token\b/ nocase ascii
344
+
345
+ condition:
346
+ any of them
347
+ }
348
+
349
+ // ── UserPromptSubmit rules ────────────────────────────────────────────────────
350
+
351
+ rule prompt_secret_promptsecret
352
+ {
353
+ meta:
354
+ sec_cat = "secret"
355
+ sec_subcat = "prompt-secret"
356
+ risk_level = "medium"
357
+ description = "User prompt contains a credential or secret reference"
358
+
359
+ strings:
360
+ $var_api_key = /\$\{?API_KEY\}?/ nocase ascii
361
+ $var_secret = /\$\{?SECRET\}?/ nocase ascii
362
+ $var_token = /\$\{?TOKEN\}?/ nocase ascii
363
+ $var_password = /\$\{?PASSWORD\}?/ nocase ascii
364
+ $var_passwd = /\$\{?PASSWD\}?/ nocase ascii
365
+ $var_access_key = /\$\{?ACCESS_KEY\}?/ nocase ascii
366
+ $var_private_key = /\$\{?PRIVATE_KEY\}?/ nocase ascii
367
+ $var_client_secret = /\$\{?CLIENT_SECRET\}?/ nocase ascii
368
+ $var_auth_token = /\$\{?AUTH_TOKEN\}?/ nocase ascii
369
+ $var_github_token = /\$\{?GITHUB_TOKEN\}?/ nocase ascii
370
+ $var_openai_key = /\$\{?OPENAI_API_KEY\}?/ nocase ascii
371
+ $var_anthropic_key = /\$\{?ANTHROPIC_API_KEY\}?/ nocase ascii
372
+ $assign_api_key = /\bAPI_KEY\s*=/ ascii
373
+ $assign_secret = /\bSECRET\s*=/ ascii
374
+ $assign_token = /\bTOKEN\s*=/ ascii
375
+
376
+ condition:
377
+ any of them
378
+ }
379
+
380
+ rule prompt_inject_promptinject
381
+ {
382
+ meta:
383
+ sec_cat = "inject"
384
+ sec_subcat = "prompt-injection"
385
+ risk_level = "medium"
386
+ description = "User prompt contains a shell injection pattern"
387
+
388
+ strings:
389
+ // | sh or | bash
390
+ $pipe_sh = /\|\s*(?:ba)?sh\b/ nocase ascii
391
+ // $( ... ) with at least 5 chars inside
392
+ $cmd_sub = /\$\([^)]{5,}\)/ ascii
393
+
394
+ condition:
395
+ any of them
396
+ }
397
+
398
+ // ── Gitleaks-derived credential patterns ──────────────────────────────────────
399
+ //
400
+ // High-confidence token/key format rules derived from the Gitleaks project
401
+ // (https://github.com/gitleaks/gitleaks — MIT licence). These match
402
+ // provider-specific key formats whose structure is publicly documented and
403
+ // effectively impossible to confuse with normal text.
404
+
405
+ // GitHub Personal Access Token (classic ghp_), GitHub App installation token
406
+ // (ghs_), and fine-grained PAT (github_pat_).
407
+ // Ref: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github
408
+ rule gitleaks_github_pat
409
+ {
410
+ meta:
411
+ sec_cat = "secret"
412
+ sec_subcat = "github-token"
413
+ risk_level = "high"
414
+ description = "GitHub Personal Access Token (ghp_), App token (ghs_), or fine-grained PAT (github_pat_)"
415
+
416
+ strings:
417
+ // Classic PAT: ghp_ + 36 alphanumeric chars
418
+ $ghp = /ghp_[0-9a-zA-Z]{36}/ ascii
419
+ // GitHub App installation token: ghs_ + 36 alphanumeric chars
420
+ $ghs = /ghs_[0-9a-zA-Z]{36}/ ascii
421
+ // Fine-grained PAT: github_pat_ + 82 alphanumeric/underscore chars
422
+ $github_pat = /github_pat_[0-9a-zA-Z_]{82}/ ascii
423
+
424
+ condition:
425
+ any of them
426
+ }
427
+
428
+ // Anthropic API key — the sk-ant- prefix is unique to Anthropic.
429
+ // Real keys are 108 chars total; the pattern uses 20+ to be forward-compatible.
430
+ rule gitleaks_anthropic_key
431
+ {
432
+ meta:
433
+ sec_cat = "secret"
434
+ sec_subcat = "anthropic-api-key"
435
+ risk_level = "high"
436
+ description = "Anthropic API key (sk-ant- prefix followed by base64url payload)"
437
+
438
+ strings:
439
+ // sk-ant- + at least 20 alphanumeric/dash/underscore chars
440
+ $sk_ant = /sk-ant-[a-zA-Z0-9\-_]{20,}/ ascii
441
+
442
+ condition:
443
+ any of them
444
+ }
445
+
446
+ // OpenAI API key formats.
447
+ // New project-scoped keys use sk-proj-; legacy service keys are sk- + 48 chars.
448
+ // Anthropic keys (sk-ant-) are excluded by the more-specific prefix patterns.
449
+ rule gitleaks_openai_key
450
+ {
451
+ meta:
452
+ sec_cat = "secret"
453
+ sec_subcat = "openai-api-key"
454
+ risk_level = "high"
455
+ description = "OpenAI API key — project-scoped (sk-proj-...) or legacy 48-char key"
456
+
457
+ strings:
458
+ // New project-scoped key: sk-proj- + 50+ alphanumeric/dash/underscore
459
+ $sk_proj = /sk-proj-[a-zA-Z0-9\-_]{50,}/ ascii
460
+ // Legacy service key: sk- + exactly 48 alphanumeric chars
461
+ // (must NOT be sk-ant- or sk-proj- — the specific length distinguishes it)
462
+ $sk_legacy = /sk-[a-zA-Z0-9]{48}/ ascii
463
+
464
+ condition:
465
+ any of them
466
+ }
467
+
468
+ // AWS Access Key ID — fixed 20-char string beginning with one of the
469
+ // documented IAM key prefixes.
470
+ // Ref: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html
471
+ rule gitleaks_aws_access_key
472
+ {
473
+ meta:
474
+ sec_cat = "secret"
475
+ sec_subcat = "aws-access-key"
476
+ risk_level = "high"
477
+ description = "AWS Access Key ID (AKIA*, AGPA*, AIDA*, AROA*, AIPA*, ANPA*, ANVA*, ASIA*, A3T*)"
478
+
479
+ strings:
480
+ // 4-char prefix + 16 uppercase alphanumeric chars = 20-char key
481
+ $aws_key = /(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}/ ascii
482
+
483
+ condition:
484
+ any of them
485
+ }
486
+
487
+ // Generic hardcoded secret assignment — catches config files, .env files, and
488
+ // source code that embeds plaintext secrets as key = "value" pairs.
489
+ // Requires at least 8 chars in the value to reduce noise from test fixtures.
490
+ rule gitleaks_generic_secret
491
+ {
492
+ meta:
493
+ sec_cat = "secret"
494
+ sec_subcat = "hardcoded-secret"
495
+ risk_level = "high"
496
+ description = "Explicit secret assignment: password/secret/api_key/token = \"value\" with 8+ char value"
497
+
498
+ strings:
499
+ // (password|passwd|secret|api_key|apikey|token|auth_token) : "value" or = "value"
500
+ $assign = /(?i)(password|passwd|secret|api_key|apikey|token|auth_token)\s*[:=]\s*["'][^"']{8,}["']/ ascii
501
+
502
+ condition:
503
+ any of them
504
+ }
505
+
506
+ // PEM/DER private key material — the canonical -----BEGIN ... PRIVATE KEY-----
507
+ // header is present in all common private key formats.
508
+ rule gitleaks_private_key
509
+ {
510
+ meta:
511
+ sec_cat = "secret"
512
+ sec_subcat = "private-key"
513
+ risk_level = "high"
514
+ description = "PEM private key header (RSA, EC, DSA, OpenSSH, or generic PRIVATE KEY block)"
515
+
516
+ strings:
517
+ // Matches -----BEGIN PRIVATE KEY-----, -----BEGIN RSA PRIVATE KEY-----, etc.
518
+ $pem = /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/ ascii
519
+
520
+ condition:
521
+ any of them
522
+ }
523
+
524
+ // JSON Web Token — three base64url-encoded segments separated by dots.
525
+ // The eyJ prefix is deterministic: base64url of '{"' is always eyJ.
526
+ rule gitleaks_jwt
527
+ {
528
+ meta:
529
+ sec_cat = "secret"
530
+ sec_subcat = "jwt-token"
531
+ risk_level = "medium"
532
+ description = "JSON Web Token (JWT) — eyJ header . payload . signature, each segment 10+ chars"
533
+
534
+ strings:
535
+ // eyJ<header>.<payload>.<signature> — each segment at least 10 base64url chars
536
+ $jwt = /eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/ ascii
537
+
538
+ condition:
539
+ any of them
540
+ }
541
+
542
+ // ── Agentic compound rules ─────────────────────────────────────────────────────
543
+ //
544
+ // These rules fire on agent dispatch payloads (Task/Agent tool calls) whose
545
+ // description text explicitly references credential or secret material. A
546
+ // parent agent instructing a sub-agent to "fetch the API key" is materially
547
+ // more concerning than a sub-agent that incidentally touches a key store.
548
+
549
+ // Fires when a Task/Agent dispatch description combines an agent-spawn keyword
550
+ // with at least two distinct credential-domain terms. The two-keyword threshold
551
+ // avoids false positives from incidental single-word matches.
552
+ rule compound_agent_credaccess
553
+ {
554
+ meta:
555
+ sec_cat = "agent-spawn"
556
+ sec_subcat = "credentialed-subagent"
557
+ risk_level = "high"
558
+ description = "Agent dispatch (Task/Agent tool) whose description explicitly references credential or secret material — sub-agent authorised to handle secrets"
559
+
560
+ strings:
561
+ // Agent dispatch indicators
562
+ $dispatch_task = "Task(" ascii
563
+ $dispatch_agent = "Agent(" ascii
564
+ $dispatch_spawn = "spawn" nocase ascii
565
+ $dispatch_deleg = "delegate" nocase ascii
566
+
567
+ // Credential-domain keywords (each counted individually)
568
+ $cred_credentials = "credentials" nocase ascii
569
+ $cred_api_key_u = "api_key" nocase ascii
570
+ $cred_api_key_s = "api key" nocase ascii
571
+ $cred_secret = "secret" nocase ascii
572
+ $cred_password = "password" nocase ascii
573
+ $cred_private_key = "private key" nocase ascii
574
+ $cred_ssh_key = "ssh key" nocase ascii
575
+
576
+ condition:
577
+ // Must look like an agent dispatch AND reference at least 2 credential terms
578
+ (any of ($dispatch_*)) and (2 of ($cred_*))
579
+ }