chainwall 0.1.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.
Files changed (348) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -0
  3. package/commands/security-scan.md +35 -0
  4. package/dist/auditor/access-mapper.d.ts +3 -0
  5. package/dist/auditor/access-mapper.d.ts.map +1 -0
  6. package/dist/auditor/access-mapper.js +15 -0
  7. package/dist/auditor/access-mapper.js.map +1 -0
  8. package/dist/auditor/cli-detector.d.ts +7 -0
  9. package/dist/auditor/cli-detector.d.ts.map +1 -0
  10. package/dist/auditor/cli-detector.js +63 -0
  11. package/dist/auditor/cli-detector.js.map +1 -0
  12. package/dist/auditor/cross-reference.d.ts +4 -0
  13. package/dist/auditor/cross-reference.d.ts.map +1 -0
  14. package/dist/auditor/cross-reference.js +16 -0
  15. package/dist/auditor/cross-reference.js.map +1 -0
  16. package/dist/auditor/env-auditor.d.ts +9 -0
  17. package/dist/auditor/env-auditor.d.ts.map +1 -0
  18. package/dist/auditor/env-auditor.js +83 -0
  19. package/dist/auditor/env-auditor.js.map +1 -0
  20. package/dist/auditor/mcp-analyzer.d.ts +11 -0
  21. package/dist/auditor/mcp-analyzer.d.ts.map +1 -0
  22. package/dist/auditor/mcp-analyzer.js +145 -0
  23. package/dist/auditor/mcp-analyzer.js.map +1 -0
  24. package/dist/auditor/mcp-detector.d.ts +17 -0
  25. package/dist/auditor/mcp-detector.d.ts.map +1 -0
  26. package/dist/auditor/mcp-detector.js +86 -0
  27. package/dist/auditor/mcp-detector.js.map +1 -0
  28. package/dist/auditor/remediation.d.ts +26 -0
  29. package/dist/auditor/remediation.d.ts.map +1 -0
  30. package/dist/auditor/remediation.js +222 -0
  31. package/dist/auditor/remediation.js.map +1 -0
  32. package/dist/auditor/tool-detector.d.ts +15 -0
  33. package/dist/auditor/tool-detector.d.ts.map +1 -0
  34. package/dist/auditor/tool-detector.js +241 -0
  35. package/dist/auditor/tool-detector.js.map +1 -0
  36. package/dist/auditor/types.d.ts +31 -0
  37. package/dist/auditor/types.d.ts.map +1 -0
  38. package/dist/auditor/types.js +2 -0
  39. package/dist/auditor/types.js.map +1 -0
  40. package/dist/auditor/vscode-extension-scanner.d.ts +8 -0
  41. package/dist/auditor/vscode-extension-scanner.d.ts.map +1 -0
  42. package/dist/auditor/vscode-extension-scanner.js +51 -0
  43. package/dist/auditor/vscode-extension-scanner.js.map +1 -0
  44. package/dist/cli.d.ts +3 -0
  45. package/dist/cli.d.ts.map +1 -0
  46. package/dist/cli.js +159 -0
  47. package/dist/cli.js.map +1 -0
  48. package/dist/commands/audit.d.ts +8 -0
  49. package/dist/commands/audit.d.ts.map +1 -0
  50. package/dist/commands/audit.js +151 -0
  51. package/dist/commands/audit.js.map +1 -0
  52. package/dist/commands/init.d.ts +2 -0
  53. package/dist/commands/init.d.ts.map +1 -0
  54. package/dist/commands/init.js +34 -0
  55. package/dist/commands/init.js.map +1 -0
  56. package/dist/commands/remediate-cli.d.ts +3 -0
  57. package/dist/commands/remediate-cli.d.ts.map +1 -0
  58. package/dist/commands/remediate-cli.js +96 -0
  59. package/dist/commands/remediate-cli.js.map +1 -0
  60. package/dist/commands/scan.d.ts +11 -0
  61. package/dist/commands/scan.d.ts.map +1 -0
  62. package/dist/commands/scan.js +138 -0
  63. package/dist/commands/scan.js.map +1 -0
  64. package/dist/commands/watch.d.ts +6 -0
  65. package/dist/commands/watch.d.ts.map +1 -0
  66. package/dist/commands/watch.js +203 -0
  67. package/dist/commands/watch.js.map +1 -0
  68. package/dist/config.d.ts +19 -0
  69. package/dist/config.d.ts.map +1 -0
  70. package/dist/config.js +235 -0
  71. package/dist/config.js.map +1 -0
  72. package/dist/mcp-server/index.d.ts +3 -0
  73. package/dist/mcp-server/index.d.ts.map +1 -0
  74. package/dist/mcp-server/index.js +69 -0
  75. package/dist/mcp-server/index.js.map +1 -0
  76. package/dist/mcp-server/schemas.d.ts +13 -0
  77. package/dist/mcp-server/schemas.d.ts.map +1 -0
  78. package/dist/mcp-server/schemas.js +13 -0
  79. package/dist/mcp-server/schemas.js.map +1 -0
  80. package/dist/mcp-server/tools/audit-status.d.ts +3 -0
  81. package/dist/mcp-server/tools/audit-status.d.ts.map +1 -0
  82. package/dist/mcp-server/tools/audit-status.js +46 -0
  83. package/dist/mcp-server/tools/audit-status.js.map +1 -0
  84. package/dist/mcp-server/tools/check-command.d.ts +4 -0
  85. package/dist/mcp-server/tools/check-command.d.ts.map +1 -0
  86. package/dist/mcp-server/tools/check-command.js +30 -0
  87. package/dist/mcp-server/tools/check-command.js.map +1 -0
  88. package/dist/mcp-server/tools/scan-content.d.ts +4 -0
  89. package/dist/mcp-server/tools/scan-content.d.ts.map +1 -0
  90. package/dist/mcp-server/tools/scan-content.js +18 -0
  91. package/dist/mcp-server/tools/scan-content.js.map +1 -0
  92. package/dist/mcp-server/tools/scan-file.d.ts +4 -0
  93. package/dist/mcp-server/tools/scan-file.d.ts.map +1 -0
  94. package/dist/mcp-server/tools/scan-file.js +48 -0
  95. package/dist/mcp-server/tools/scan-file.js.map +1 -0
  96. package/dist/mcp-server/types.d.ts +15 -0
  97. package/dist/mcp-server/types.d.ts.map +1 -0
  98. package/dist/mcp-server/types.js +2 -0
  99. package/dist/mcp-server/types.js.map +1 -0
  100. package/dist/reporter/audit-report.d.ts +4 -0
  101. package/dist/reporter/audit-report.d.ts.map +1 -0
  102. package/dist/reporter/audit-report.js +186 -0
  103. package/dist/reporter/audit-report.js.map +1 -0
  104. package/dist/reporter/json-report.d.ts +3 -0
  105. package/dist/reporter/json-report.d.ts.map +1 -0
  106. package/dist/reporter/json-report.js +4 -0
  107. package/dist/reporter/json-report.js.map +1 -0
  108. package/dist/reporter/remediation-text.d.ts +3 -0
  109. package/dist/reporter/remediation-text.d.ts.map +1 -0
  110. package/dist/reporter/remediation-text.js +12 -0
  111. package/dist/reporter/remediation-text.js.map +1 -0
  112. package/dist/reporter/risk-scorer.d.ts +8 -0
  113. package/dist/reporter/risk-scorer.d.ts.map +1 -0
  114. package/dist/reporter/risk-scorer.js +40 -0
  115. package/dist/reporter/risk-scorer.js.map +1 -0
  116. package/dist/reporter/sarif-report.d.ts +3 -0
  117. package/dist/reporter/sarif-report.d.ts.map +1 -0
  118. package/dist/reporter/sarif-report.js +80 -0
  119. package/dist/reporter/sarif-report.js.map +1 -0
  120. package/dist/reporter/shared.d.ts +11 -0
  121. package/dist/reporter/shared.d.ts.map +1 -0
  122. package/dist/reporter/shared.js +85 -0
  123. package/dist/reporter/shared.js.map +1 -0
  124. package/dist/reporter/summary-generator.d.ts +16 -0
  125. package/dist/reporter/summary-generator.d.ts.map +1 -0
  126. package/dist/reporter/summary-generator.js +89 -0
  127. package/dist/reporter/summary-generator.js.map +1 -0
  128. package/dist/reporter/terminal-report.d.ts +4 -0
  129. package/dist/reporter/terminal-report.d.ts.map +1 -0
  130. package/dist/reporter/terminal-report.js +135 -0
  131. package/dist/reporter/terminal-report.js.map +1 -0
  132. package/dist/rules/crypto-rules.d.ts +3 -0
  133. package/dist/rules/crypto-rules.d.ts.map +1 -0
  134. package/dist/rules/crypto-rules.js +252 -0
  135. package/dist/rules/crypto-rules.js.map +1 -0
  136. package/dist/rules/default-rules.d.ts +9 -0
  137. package/dist/rules/default-rules.d.ts.map +1 -0
  138. package/dist/rules/default-rules.js +1319 -0
  139. package/dist/rules/default-rules.js.map +1 -0
  140. package/dist/rules/index.d.ts +7 -0
  141. package/dist/rules/index.d.ts.map +1 -0
  142. package/dist/rules/index.js +7 -0
  143. package/dist/rules/index.js.map +1 -0
  144. package/dist/rules/injection-rules.d.ts +8 -0
  145. package/dist/rules/injection-rules.d.ts.map +1 -0
  146. package/dist/rules/injection-rules.js +108 -0
  147. package/dist/rules/injection-rules.js.map +1 -0
  148. package/dist/rules/types.d.ts +52 -0
  149. package/dist/rules/types.d.ts.map +1 -0
  150. package/dist/rules/types.js +2 -0
  151. package/dist/rules/types.js.map +1 -0
  152. package/dist/scanner/filesystem-scanner.d.ts +26 -0
  153. package/dist/scanner/filesystem-scanner.d.ts.map +1 -0
  154. package/dist/scanner/filesystem-scanner.js +369 -0
  155. package/dist/scanner/filesystem-scanner.js.map +1 -0
  156. package/dist/scanner/injection-scanner.d.ts +12 -0
  157. package/dist/scanner/injection-scanner.d.ts.map +1 -0
  158. package/dist/scanner/injection-scanner.js +136 -0
  159. package/dist/scanner/injection-scanner.js.map +1 -0
  160. package/dist/scanner/permission-checker.d.ts +4 -0
  161. package/dist/scanner/permission-checker.d.ts.map +1 -0
  162. package/dist/scanner/permission-checker.js +37 -0
  163. package/dist/scanner/permission-checker.js.map +1 -0
  164. package/dist/scanner/redact.d.ts +3 -0
  165. package/dist/scanner/redact.d.ts.map +1 -0
  166. package/dist/scanner/redact.js +17 -0
  167. package/dist/scanner/redact.js.map +1 -0
  168. package/dist/scanner/rule-engine.d.ts +9 -0
  169. package/dist/scanner/rule-engine.d.ts.map +1 -0
  170. package/dist/scanner/rule-engine.js +129 -0
  171. package/dist/scanner/rule-engine.js.map +1 -0
  172. package/dist/scanner/system-targets.d.ts +17 -0
  173. package/dist/scanner/system-targets.d.ts.map +1 -0
  174. package/dist/scanner/system-targets.js +81 -0
  175. package/dist/scanner/system-targets.js.map +1 -0
  176. package/dist/tui/App.d.ts +6 -0
  177. package/dist/tui/App.d.ts.map +1 -0
  178. package/dist/tui/App.js +224 -0
  179. package/dist/tui/App.js.map +1 -0
  180. package/dist/tui/components/BootSequence.d.ts +6 -0
  181. package/dist/tui/components/BootSequence.d.ts.map +1 -0
  182. package/dist/tui/components/BootSequence.js +40 -0
  183. package/dist/tui/components/BootSequence.js.map +1 -0
  184. package/dist/tui/components/BorderedSection.d.ts +12 -0
  185. package/dist/tui/components/BorderedSection.d.ts.map +1 -0
  186. package/dist/tui/components/BorderedSection.js +7 -0
  187. package/dist/tui/components/BorderedSection.js.map +1 -0
  188. package/dist/tui/components/ErrorBoundary.d.ts +18 -0
  189. package/dist/tui/components/ErrorBoundary.d.ts.map +1 -0
  190. package/dist/tui/components/ErrorBoundary.js +36 -0
  191. package/dist/tui/components/ErrorBoundary.js.map +1 -0
  192. package/dist/tui/components/FirstUseHint.d.ts +7 -0
  193. package/dist/tui/components/FirstUseHint.d.ts.map +1 -0
  194. package/dist/tui/components/FirstUseHint.js +20 -0
  195. package/dist/tui/components/FirstUseHint.js.map +1 -0
  196. package/dist/tui/components/Footer.d.ts +10 -0
  197. package/dist/tui/components/Footer.d.ts.map +1 -0
  198. package/dist/tui/components/Footer.js +51 -0
  199. package/dist/tui/components/Footer.js.map +1 -0
  200. package/dist/tui/components/MetricCard.d.ts +11 -0
  201. package/dist/tui/components/MetricCard.d.ts.map +1 -0
  202. package/dist/tui/components/MetricCard.js +8 -0
  203. package/dist/tui/components/MetricCard.js.map +1 -0
  204. package/dist/tui/components/Panel.d.ts +15 -0
  205. package/dist/tui/components/Panel.d.ts.map +1 -0
  206. package/dist/tui/components/Panel.js +25 -0
  207. package/dist/tui/components/Panel.js.map +1 -0
  208. package/dist/tui/components/RemediationMenu.d.ts +10 -0
  209. package/dist/tui/components/RemediationMenu.d.ts.map +1 -0
  210. package/dist/tui/components/RemediationMenu.js +84 -0
  211. package/dist/tui/components/RemediationMenu.js.map +1 -0
  212. package/dist/tui/components/RiskGauge.d.ts +7 -0
  213. package/dist/tui/components/RiskGauge.d.ts.map +1 -0
  214. package/dist/tui/components/RiskGauge.js +55 -0
  215. package/dist/tui/components/RiskGauge.js.map +1 -0
  216. package/dist/tui/components/ScrollableList.d.ts +11 -0
  217. package/dist/tui/components/ScrollableList.d.ts.map +1 -0
  218. package/dist/tui/components/ScrollableList.js +14 -0
  219. package/dist/tui/components/ScrollableList.js.map +1 -0
  220. package/dist/tui/components/Section.d.ts +9 -0
  221. package/dist/tui/components/Section.d.ts.map +1 -0
  222. package/dist/tui/components/Section.js +7 -0
  223. package/dist/tui/components/Section.js.map +1 -0
  224. package/dist/tui/components/SectionHeader.d.ts +8 -0
  225. package/dist/tui/components/SectionHeader.d.ts.map +1 -0
  226. package/dist/tui/components/SectionHeader.js +15 -0
  227. package/dist/tui/components/SectionHeader.js.map +1 -0
  228. package/dist/tui/components/SeverityBadge.d.ts +5 -0
  229. package/dist/tui/components/SeverityBadge.d.ts.map +1 -0
  230. package/dist/tui/components/SeverityBadge.js +7 -0
  231. package/dist/tui/components/SeverityBadge.js.map +1 -0
  232. package/dist/tui/components/Sidebar.d.ts +2 -0
  233. package/dist/tui/components/Sidebar.d.ts.map +1 -0
  234. package/dist/tui/components/Sidebar.js +40 -0
  235. package/dist/tui/components/Sidebar.js.map +1 -0
  236. package/dist/tui/components/StatusIndicator.d.ts +8 -0
  237. package/dist/tui/components/StatusIndicator.d.ts.map +1 -0
  238. package/dist/tui/components/StatusIndicator.js +15 -0
  239. package/dist/tui/components/StatusIndicator.js.map +1 -0
  240. package/dist/tui/components/Table.d.ts +21 -0
  241. package/dist/tui/components/Table.d.ts.map +1 -0
  242. package/dist/tui/components/Table.js +38 -0
  243. package/dist/tui/components/Table.js.map +1 -0
  244. package/dist/tui/components/Transition.d.ts +8 -0
  245. package/dist/tui/components/Transition.d.ts.map +1 -0
  246. package/dist/tui/components/Transition.js +38 -0
  247. package/dist/tui/components/Transition.js.map +1 -0
  248. package/dist/tui/components/WelcomeScreen.d.ts +6 -0
  249. package/dist/tui/components/WelcomeScreen.d.ts.map +1 -0
  250. package/dist/tui/components/WelcomeScreen.js +14 -0
  251. package/dist/tui/components/WelcomeScreen.js.map +1 -0
  252. package/dist/tui/educational.d.ts +32 -0
  253. package/dist/tui/educational.d.ts.map +1 -0
  254. package/dist/tui/educational.js +117 -0
  255. package/dist/tui/educational.js.map +1 -0
  256. package/dist/tui/hooks/useAudit.d.ts +24 -0
  257. package/dist/tui/hooks/useAudit.d.ts.map +1 -0
  258. package/dist/tui/hooks/useAudit.js +263 -0
  259. package/dist/tui/hooks/useAudit.js.map +1 -0
  260. package/dist/tui/hooks/useConfig.d.ts +18 -0
  261. package/dist/tui/hooks/useConfig.d.ts.map +1 -0
  262. package/dist/tui/hooks/useConfig.js +85 -0
  263. package/dist/tui/hooks/useConfig.js.map +1 -0
  264. package/dist/tui/hooks/useHookStatus.d.ts +10 -0
  265. package/dist/tui/hooks/useHookStatus.d.ts.map +1 -0
  266. package/dist/tui/hooks/useHookStatus.js +59 -0
  267. package/dist/tui/hooks/useHookStatus.js.map +1 -0
  268. package/dist/tui/hooks/useLogs.d.ts +42 -0
  269. package/dist/tui/hooks/useLogs.d.ts.map +1 -0
  270. package/dist/tui/hooks/useLogs.js +105 -0
  271. package/dist/tui/hooks/useLogs.js.map +1 -0
  272. package/dist/tui/hooks/useScan.d.ts +39 -0
  273. package/dist/tui/hooks/useScan.d.ts.map +1 -0
  274. package/dist/tui/hooks/useScan.js +255 -0
  275. package/dist/tui/hooks/useScan.js.map +1 -0
  276. package/dist/tui/hooks/useTerminalSize.d.ts +10 -0
  277. package/dist/tui/hooks/useTerminalSize.d.ts.map +1 -0
  278. package/dist/tui/hooks/useTerminalSize.js +27 -0
  279. package/dist/tui/hooks/useTerminalSize.js.map +1 -0
  280. package/dist/tui/index.d.ts +2 -0
  281. package/dist/tui/index.d.ts.map +1 -0
  282. package/dist/tui/index.js +8 -0
  283. package/dist/tui/index.js.map +1 -0
  284. package/dist/tui/screens/AuditPanel.d.ts +7 -0
  285. package/dist/tui/screens/AuditPanel.d.ts.map +1 -0
  286. package/dist/tui/screens/AuditPanel.js +467 -0
  287. package/dist/tui/screens/AuditPanel.js.map +1 -0
  288. package/dist/tui/screens/LogsPanel.d.ts +2 -0
  289. package/dist/tui/screens/LogsPanel.d.ts.map +1 -0
  290. package/dist/tui/screens/LogsPanel.js +127 -0
  291. package/dist/tui/screens/LogsPanel.js.map +1 -0
  292. package/dist/tui/screens/OverviewPanel.d.ts +2 -0
  293. package/dist/tui/screens/OverviewPanel.d.ts.map +1 -0
  294. package/dist/tui/screens/OverviewPanel.js +84 -0
  295. package/dist/tui/screens/OverviewPanel.js.map +1 -0
  296. package/dist/tui/screens/ScanPanel.d.ts +2 -0
  297. package/dist/tui/screens/ScanPanel.d.ts.map +1 -0
  298. package/dist/tui/screens/ScanPanel.js +188 -0
  299. package/dist/tui/screens/ScanPanel.js.map +1 -0
  300. package/dist/tui/screens/ScanResultsPanel.d.ts +2 -0
  301. package/dist/tui/screens/ScanResultsPanel.d.ts.map +1 -0
  302. package/dist/tui/screens/ScanResultsPanel.js +394 -0
  303. package/dist/tui/screens/ScanResultsPanel.js.map +1 -0
  304. package/dist/tui/screens/SettingsPanel.d.ts +2 -0
  305. package/dist/tui/screens/SettingsPanel.d.ts.map +1 -0
  306. package/dist/tui/screens/SettingsPanel.js +353 -0
  307. package/dist/tui/screens/SettingsPanel.js.map +1 -0
  308. package/dist/tui/state.d.ts +35 -0
  309. package/dist/tui/state.d.ts.map +1 -0
  310. package/dist/tui/state.js +13 -0
  311. package/dist/tui/state.js.map +1 -0
  312. package/dist/tui/theme.d.ts +58 -0
  313. package/dist/tui/theme.d.ts.map +1 -0
  314. package/dist/tui/theme.js +80 -0
  315. package/dist/tui/theme.js.map +1 -0
  316. package/dist/version.d.ts +2 -0
  317. package/dist/version.d.ts.map +1 -0
  318. package/dist/version.js +5 -0
  319. package/dist/version.js.map +1 -0
  320. package/hooks/audit-logger.sh +74 -0
  321. package/hooks/detection-lib.sh +301 -0
  322. package/hooks/git-pre-commit.sh +195 -0
  323. package/hooks/git-pre-push.sh +125 -0
  324. package/hooks/git-safety.sh +152 -0
  325. package/hooks/security-scanner.sh +527 -0
  326. package/install.sh +543 -0
  327. package/package.json +67 -0
  328. package/patterns/credentials.yaml +317 -0
  329. package/patterns/dangerous-commands.yaml +167 -0
  330. package/patterns/pii.yaml +95 -0
  331. package/patterns/prompt-injection.yaml +131 -0
  332. package/patterns/supply-chain.yaml +119 -0
  333. package/rules/AGENTS.md +60 -0
  334. package/rules/SECURITY-RULES.md +177 -0
  335. package/rules/claude.md +9 -0
  336. package/rules/clinerules +29 -0
  337. package/rules/continuerules +29 -0
  338. package/rules/copilot-instructions.md +9 -0
  339. package/rules/cursor-security.mdc +14 -0
  340. package/rules/gemini.md +9 -0
  341. package/rules/kiro-security.md +29 -0
  342. package/rules/roocode-security.md +29 -0
  343. package/rules/trae-security.md +29 -0
  344. package/rules/windsurfrules +9 -0
  345. package/skill/llm-antivirus/SKILL.md +73 -0
  346. package/skill/llm-antivirus/references/threat-patterns.yaml +82 -0
  347. package/skill/llm-antivirus/scripts/security-audit.sh +244 -0
  348. package/uninstall.sh +215 -0
@@ -0,0 +1,1319 @@
1
+ /**
2
+ * PEM key header validation: reject matches that appear inside pattern/regex
3
+ * definitions (e.g. in security tool source, YAML pattern databases, docs).
4
+ * A real PEM key header appears as its own line; in code, it's wrapped in
5
+ * regex delimiters, quotes next to pattern: keys, bash =~ operators, etc.
6
+ */
7
+ function validatePEMHeader(match, line) {
8
+ const trimmed = line.trim();
9
+ // If the line is exactly the PEM header, it's a real key
10
+ if (trimmed === match[0])
11
+ return true;
12
+ const idx = line.indexOf(match[0]);
13
+ if (idx < 0)
14
+ return true; // safety fallback
15
+ const before = line.slice(0, idx);
16
+ const afterRaw = line.slice(idx + match[0].length);
17
+ const afterChar = afterRaw.trimStart().charAt(0);
18
+ // Regex literal: /-----BEGIN.../
19
+ if (before.trimEnd().endsWith('/'))
20
+ return false;
21
+ // Match immediately preceded by quote (string/assignment context, not a real PEM file)
22
+ if (before.endsWith('"') || before.endsWith("'"))
23
+ return false;
24
+ // Closing regex or string delimiter immediately after
25
+ if (afterChar === '/' || afterChar === '`')
26
+ return false;
27
+ // Pattern/regex config key: "pattern:", "regex:", etc.
28
+ if (/\b(pattern|regex|regexp|rule_?name|detect)\s*[:=]/i.test(before))
29
+ return false;
30
+ // Bash regex operator: =~
31
+ if (before.includes('=~'))
32
+ return false;
33
+ // Bash string comparison: [[ "$var" == *"-----BEGIN..."* ]]
34
+ if (/\[\[.*==\s*\*?"/.test(before))
35
+ return false;
36
+ // Bash block/echo referencing the pattern: block "..." "..." "-----BEGIN..."
37
+ if (/\b(block|echo|printf|log)\b/.test(before) && before.includes('"'))
38
+ return false;
39
+ // grep/sed/awk/rg command context
40
+ if (/\b(grep|awk|sed|rg)\b/.test(before))
41
+ return false;
42
+ // Test assertion context
43
+ if (/\b(expect|assert|test|describe|it)\s*\(/.test(before))
44
+ return false;
45
+ // YAML pattern value (line starts with whitespace + key: then quoted match)
46
+ if (/^\s+\w+:\s*["']/.test(line))
47
+ return false;
48
+ // Markdown code/list context: starts with backtick, dash, or bullet
49
+ if (/^\s*[-*`|]/.test(trimmed) && trimmed !== match[0])
50
+ return false;
51
+ return true;
52
+ }
53
+ // SSN validation: reject 000, 666, 900+ first groups; reject 00 middle, 0000 last
54
+ function validateSSN(match) {
55
+ const full = match[0];
56
+ const parts = full.match(/(\d{3})-(\d{2})-(\d{4})/);
57
+ if (!parts)
58
+ return false;
59
+ const first = parseInt(parts[1], 10);
60
+ const middle = parts[2];
61
+ const last = parts[3];
62
+ if (first === 0 || first === 666 || first >= 900)
63
+ return false;
64
+ if (middle === '00')
65
+ return false;
66
+ if (last === '0000')
67
+ return false;
68
+ return true;
69
+ }
70
+ // Luhn algorithm: validates credit card check digit
71
+ function luhnCheck(digits) {
72
+ let sum = 0;
73
+ let alternate = false;
74
+ for (let i = digits.length - 1; i >= 0; i--) {
75
+ let n = parseInt(digits[i], 10);
76
+ if (alternate) {
77
+ n *= 2;
78
+ if (n > 9)
79
+ n -= 9;
80
+ }
81
+ sum += n;
82
+ alternate = !alternate;
83
+ }
84
+ return sum % 10 === 0;
85
+ }
86
+ // Credit card BIN validation: 4=Visa, 51-55=MC, 34/37=Amex (15 digits), 60/65=Discover
87
+ function validateCreditCard(match) {
88
+ const digits = match[0].replace(/[-\s]/g, '');
89
+ if (digits.length < 15)
90
+ return false;
91
+ if (!luhnCheck(digits))
92
+ return false;
93
+ const first1 = digits[0];
94
+ const first2 = digits.substring(0, 2);
95
+ if (['34', '37'].includes(first2))
96
+ return true; // Amex (15 digits)
97
+ if (digits.length < 16)
98
+ return false;
99
+ if (first1 === '4')
100
+ return true; // Visa
101
+ if (['51', '52', '53', '54', '55'].includes(first2))
102
+ return true; // Mastercard
103
+ if (['60', '65'].includes(first2))
104
+ return true; // Discover
105
+ return false;
106
+ }
107
+ export const credentialRules = [
108
+ // ── AWS ──────────────────────────────────────────────────────────────
109
+ {
110
+ id: 'aws-access-key-id',
111
+ name: 'AWS Access Key ID',
112
+ regex: /AKIA[0-9A-Z]{16}/,
113
+ severity: 'critical',
114
+ category: 'credential',
115
+ description: 'AWS IAM access key — grants programmatic access to AWS services',
116
+ },
117
+ {
118
+ id: 'aws-secret-access-key',
119
+ name: 'AWS Secret Access Key',
120
+ regex: /aws_secret_access_key["'\s=:]+[A-Za-z0-9/+=]{40}/i,
121
+ severity: 'critical',
122
+ category: 'credential',
123
+ description: 'AWS secret key paired with access key ID',
124
+ },
125
+ {
126
+ id: 'aws-session-token',
127
+ name: 'AWS Session Token',
128
+ regex: /aws_session_token["'\s=:]+[A-Za-z0-9/+=]{100,}/i,
129
+ severity: 'critical',
130
+ category: 'credential',
131
+ description: 'Temporary AWS session token from STS',
132
+ },
133
+ // ── GCP / Google ─────────────────────────────────────────────────────
134
+ {
135
+ id: 'google-api-key',
136
+ name: 'Google API Key',
137
+ regex: /AIza[0-9A-Za-z_-]{35}/,
138
+ severity: 'high',
139
+ category: 'credential',
140
+ description: 'Google Cloud / Maps / Firebase API key',
141
+ },
142
+ {
143
+ id: 'gcp-service-account-key',
144
+ name: 'GCP Service Account Key',
145
+ regex: /"type":\s*"service_account"/,
146
+ severity: 'critical',
147
+ category: 'credential',
148
+ description: 'GCP service account JSON key file marker',
149
+ },
150
+ {
151
+ id: 'google-oauth-client-secret',
152
+ name: 'Google OAuth Client Secret',
153
+ regex: /client_secret["'\s=:]+[A-Za-z0-9_-]{24,}/i,
154
+ severity: 'high',
155
+ category: 'credential',
156
+ description: 'Google OAuth2 client secret',
157
+ },
158
+ // ── Azure ────────────────────────────────────────────────────────────
159
+ {
160
+ id: 'azure-storage-account-key',
161
+ name: 'Azure Storage Account Key',
162
+ regex: /(AccountKey|azure_storage_key)["'\s=:]+[A-Za-z0-9/+=]{86,88}==/i,
163
+ severity: 'critical',
164
+ category: 'credential',
165
+ description: 'Azure Storage account access key',
166
+ },
167
+ {
168
+ id: 'azure-ad-client-secret',
169
+ name: 'Azure AD Client Secret',
170
+ regex: /(client_secret|azure_client_secret)["'\s=:]+[A-Za-z0-9_.~-]{34,}/i,
171
+ severity: 'high',
172
+ category: 'credential',
173
+ description: 'Azure Active Directory application secret',
174
+ },
175
+ {
176
+ id: 'azure-connection-string',
177
+ name: 'Azure Connection String',
178
+ regex: /DefaultEndpointsProtocol=https;AccountName=[^;]+;AccountKey=[A-Za-z0-9/+=]{86,88}==/,
179
+ severity: 'critical',
180
+ category: 'credential',
181
+ description: 'Azure Storage connection string with embedded key',
182
+ },
183
+ // ── GitHub ───────────────────────────────────────────────────────────
184
+ {
185
+ id: 'github-personal-access-token',
186
+ name: 'GitHub Personal Access Token',
187
+ regex: /ghp_[a-zA-Z0-9]{36,}/,
188
+ severity: 'critical',
189
+ category: 'credential',
190
+ description: 'GitHub classic personal access token',
191
+ validate: (match) => match[0].length <= 200,
192
+ },
193
+ {
194
+ id: 'github-fine-grained-token',
195
+ name: 'GitHub Fine-Grained Token',
196
+ regex: /github_pat_[a-zA-Z0-9]{22,}_[a-zA-Z0-9]{59,}/,
197
+ severity: 'critical',
198
+ category: 'credential',
199
+ description: 'GitHub fine-grained personal access token',
200
+ validate: (match) => match[0].length <= 200,
201
+ },
202
+ {
203
+ id: 'github-oauth-access-token',
204
+ name: 'GitHub OAuth Access Token',
205
+ regex: /gho_[a-zA-Z0-9]{36,}/,
206
+ severity: 'high',
207
+ category: 'credential',
208
+ description: 'GitHub OAuth access token',
209
+ validate: (match) => match[0].length <= 200,
210
+ },
211
+ {
212
+ id: 'github-app-token',
213
+ name: 'GitHub App Token',
214
+ regex: /(ghu|ghs)_[a-zA-Z0-9]{36,}/,
215
+ severity: 'high',
216
+ category: 'credential',
217
+ description: 'GitHub App user-to-server or server-to-server token',
218
+ validate: (match) => match[0].length <= 200,
219
+ },
220
+ {
221
+ id: 'github-app-refresh-token',
222
+ name: 'GitHub App Refresh Token',
223
+ regex: /ghr_[a-zA-Z0-9]{36,}/,
224
+ severity: 'high',
225
+ category: 'credential',
226
+ description: 'GitHub App refresh token',
227
+ validate: (match) => match[0].length <= 200,
228
+ },
229
+ // ── GitLab ───────────────────────────────────────────────────────────
230
+ {
231
+ id: 'gitlab-personal-access-token',
232
+ name: 'GitLab Personal Access Token',
233
+ regex: /glpat-[a-zA-Z0-9_-]{20,}/,
234
+ severity: 'critical',
235
+ category: 'credential',
236
+ description: 'GitLab personal access token',
237
+ },
238
+ {
239
+ id: 'gitlab-pipeline-token',
240
+ name: 'GitLab Pipeline Token',
241
+ regex: /glptt-[a-zA-Z0-9_-]{20,}/,
242
+ severity: 'high',
243
+ category: 'credential',
244
+ description: 'GitLab pipeline trigger token',
245
+ },
246
+ {
247
+ id: 'gitlab-runner-token',
248
+ name: 'GitLab Runner Token',
249
+ regex: /glrt-[a-zA-Z0-9_-]{20,}/,
250
+ severity: 'high',
251
+ category: 'credential',
252
+ description: 'GitLab runner registration token',
253
+ },
254
+ // ── Slack ────────────────────────────────────────────────────────────
255
+ {
256
+ id: 'slack-bot-user-token',
257
+ name: 'Slack Bot/User Token',
258
+ regex: /xox[pboa]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,}/,
259
+ severity: 'critical',
260
+ category: 'credential',
261
+ description: 'Slack API token (bot, user, app, or OAuth)',
262
+ },
263
+ {
264
+ id: 'slack-webhook-url',
265
+ name: 'Slack Webhook URL',
266
+ regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]{8,}\/B[A-Z0-9]{8,}\/[a-zA-Z0-9]{24,}/,
267
+ severity: 'high',
268
+ category: 'credential',
269
+ description: 'Slack incoming webhook URL',
270
+ },
271
+ // ── Stripe ───────────────────────────────────────────────────────────
272
+ {
273
+ id: 'stripe-secret-key',
274
+ name: 'Stripe Secret Key',
275
+ regex: /sk_(live|test)_[a-zA-Z0-9]{24,}/,
276
+ severity: 'critical',
277
+ category: 'credential',
278
+ description: 'Stripe API secret key (live or test mode)',
279
+ },
280
+ {
281
+ id: 'stripe-restricted-key',
282
+ name: 'Stripe Restricted Key',
283
+ regex: /rk_(live|test)_[a-zA-Z0-9]{24,}/,
284
+ severity: 'high',
285
+ category: 'credential',
286
+ description: 'Stripe restricted API key',
287
+ },
288
+ {
289
+ id: 'stripe-webhook-secret',
290
+ name: 'Stripe Webhook Secret',
291
+ regex: /whsec_[a-zA-Z0-9]{32,}/,
292
+ severity: 'high',
293
+ category: 'credential',
294
+ description: 'Stripe webhook signing secret',
295
+ },
296
+ // ── OpenAI / Anthropic ──────────────────────────────────────────────
297
+ {
298
+ id: 'openai-api-key',
299
+ name: 'OpenAI API Key',
300
+ regex: /sk-(?!ant-)[a-zA-Z0-9]{48}/,
301
+ severity: 'critical',
302
+ category: 'credential',
303
+ description: 'OpenAI API key for GPT/DALL-E/Whisper access',
304
+ },
305
+ {
306
+ id: 'openai-project-key',
307
+ name: 'OpenAI Project Key',
308
+ regex: /sk-proj-[a-zA-Z0-9_-]{48,}/,
309
+ severity: 'critical',
310
+ category: 'credential',
311
+ description: 'OpenAI project-scoped API key',
312
+ },
313
+ {
314
+ id: 'anthropic-api-key',
315
+ name: 'Anthropic API Key',
316
+ regex: /sk-ant-[a-zA-Z0-9_-]{40,}/,
317
+ severity: 'critical',
318
+ category: 'credential',
319
+ description: 'Anthropic API key for Claude access',
320
+ },
321
+ // ── Twilio ───────────────────────────────────────────────────────────
322
+ {
323
+ id: 'twilio-api-key',
324
+ name: 'Twilio API Key',
325
+ regex: /SK[a-f0-9]{32}/,
326
+ severity: 'high',
327
+ category: 'credential',
328
+ description: 'Twilio API key (SK prefix + 32 hex chars)',
329
+ },
330
+ {
331
+ id: 'twilio-account-sid',
332
+ name: 'Twilio Account SID',
333
+ regex: /AC[a-f0-9]{32}/,
334
+ severity: 'medium',
335
+ category: 'credential',
336
+ description: 'Twilio Account SID (not secret but sensitive identifier)',
337
+ },
338
+ // ── SendGrid ─────────────────────────────────────────────────────────
339
+ {
340
+ id: 'sendgrid-api-key',
341
+ name: 'SendGrid API Key',
342
+ regex: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/,
343
+ severity: 'critical',
344
+ category: 'credential',
345
+ description: 'SendGrid API key for email sending',
346
+ },
347
+ // ── Supabase ─────────────────────────────────────────────────────────
348
+ {
349
+ id: 'supabase-service-role-key',
350
+ name: 'Supabase Service Role Key',
351
+ regex: /(supabase_service_role_key|SUPABASE_SERVICE_KEY)["'\s=:]+eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/i,
352
+ severity: 'critical',
353
+ category: 'credential',
354
+ description: 'Supabase service role JWT — bypasses Row Level Security',
355
+ },
356
+ {
357
+ id: 'supabase-anon-key',
358
+ name: 'Supabase Anon Key (exposed)',
359
+ regex: /supabase_anon_key["'\s=:]+eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/i,
360
+ severity: 'medium',
361
+ category: 'credential',
362
+ description: 'Supabase anonymous key — public but sensitive in server context',
363
+ },
364
+ // ── Firebase ─────────────────────────────────────────────────────────
365
+ {
366
+ id: 'firebase-server-key',
367
+ name: 'Firebase Server Key',
368
+ regex: /AAAA[a-zA-Z0-9_-]{7,}:[a-zA-Z0-9_-]{140,}/,
369
+ severity: 'critical',
370
+ category: 'credential',
371
+ description: 'Firebase Cloud Messaging server key',
372
+ },
373
+ // ── Databricks ───────────────────────────────────────────────────────
374
+ {
375
+ id: 'databricks-access-token',
376
+ name: 'Databricks Access Token',
377
+ regex: /dapi[a-f0-9]{32}/,
378
+ severity: 'high',
379
+ category: 'credential',
380
+ description: 'Databricks personal access token',
381
+ },
382
+ // ── npm / PyPI / Docker ──────────────────────────────────────────────
383
+ {
384
+ id: 'npm-access-token',
385
+ name: 'npm Access Token',
386
+ regex: /npm_[a-zA-Z0-9]{36}/,
387
+ severity: 'critical',
388
+ category: 'credential',
389
+ description: 'npm registry authentication token',
390
+ },
391
+ {
392
+ id: 'pypi-api-token',
393
+ name: 'PyPI API Token',
394
+ regex: /pypi-[a-zA-Z0-9_-]{50,}/,
395
+ severity: 'critical',
396
+ category: 'credential',
397
+ description: 'PyPI package repository API token',
398
+ },
399
+ {
400
+ id: 'docker-hub-access-token',
401
+ name: 'Docker Hub Access Token',
402
+ regex: /dckr_pat_[a-zA-Z0-9_-]{20,}/,
403
+ severity: 'high',
404
+ category: 'credential',
405
+ description: 'Docker Hub personal access token',
406
+ },
407
+ // ── JWT / Bearer ─────────────────────────────────────────────────────
408
+ {
409
+ id: 'json-web-token',
410
+ name: 'JSON Web Token',
411
+ regex: /eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/,
412
+ severity: 'medium',
413
+ category: 'credential',
414
+ description: 'JWT token (may contain sensitive claims)',
415
+ },
416
+ {
417
+ id: 'bearer-token',
418
+ name: 'Bearer Token',
419
+ regex: /Bearer\s+[a-zA-Z0-9_-]{20,}/,
420
+ severity: 'medium',
421
+ category: 'credential',
422
+ description: 'Authorization Bearer token in header format',
423
+ validate: (match) => {
424
+ // Extract the token part after "Bearer "
425
+ const token = match[0].replace(/^Bearer\s+/, '');
426
+ // Reject known test/example tokens
427
+ if (token.startsWith('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'))
428
+ return false;
429
+ // Calculate Shannon entropy — reject low-entropy tokens (likely examples/placeholders)
430
+ const freq = new Map();
431
+ for (const ch of token)
432
+ freq.set(ch, (freq.get(ch) || 0) + 1);
433
+ let entropy = 0;
434
+ for (const count of freq.values()) {
435
+ const p = count / token.length;
436
+ entropy -= p * Math.log2(p);
437
+ }
438
+ return entropy > 3.5;
439
+ },
440
+ },
441
+ // ── SSH / PGP ────────────────────────────────────────────────────────
442
+ {
443
+ id: 'rsa-private-key',
444
+ name: 'RSA Private Key',
445
+ regex: /-----BEGIN RSA PRIVATE KEY-----/,
446
+ severity: 'critical',
447
+ category: 'private_key',
448
+ description: 'PEM-encoded RSA private key header',
449
+ validate: validatePEMHeader,
450
+ },
451
+ {
452
+ id: 'dsa-private-key',
453
+ name: 'DSA Private Key',
454
+ regex: /-----BEGIN DSA PRIVATE KEY-----/,
455
+ severity: 'critical',
456
+ category: 'private_key',
457
+ description: 'PEM-encoded DSA private key header',
458
+ validate: validatePEMHeader,
459
+ },
460
+ {
461
+ id: 'ec-private-key',
462
+ name: 'EC Private Key',
463
+ regex: /-----BEGIN EC PRIVATE KEY-----/,
464
+ severity: 'critical',
465
+ category: 'private_key',
466
+ description: 'PEM-encoded Elliptic Curve private key header',
467
+ validate: validatePEMHeader,
468
+ },
469
+ {
470
+ id: 'openssh-private-key',
471
+ name: 'OpenSSH Private Key',
472
+ regex: /-----BEGIN OPENSSH PRIVATE KEY-----/,
473
+ severity: 'critical',
474
+ category: 'private_key',
475
+ description: 'OpenSSH format private key header',
476
+ validate: validatePEMHeader,
477
+ },
478
+ {
479
+ id: 'pgp-private-key-block',
480
+ name: 'PGP Private Key Block',
481
+ regex: /-----BEGIN PGP PRIVATE KEY BLOCK-----/,
482
+ severity: 'critical',
483
+ category: 'private_key',
484
+ description: 'PGP/GPG private key block header',
485
+ validate: validatePEMHeader,
486
+ },
487
+ // ── Hashicorp Vault ──────────────────────────────────────────────────
488
+ {
489
+ id: 'vault-token',
490
+ name: 'Vault Token',
491
+ regex: /hvs\.[a-zA-Z0-9_-]{24,}/,
492
+ severity: 'critical',
493
+ category: 'credential',
494
+ description: 'HashiCorp Vault service token',
495
+ },
496
+ {
497
+ id: 'vault-batch-token',
498
+ name: 'Vault Batch Token',
499
+ regex: /hvb\.[a-zA-Z0-9_-]{24,}/,
500
+ severity: 'high',
501
+ category: 'credential',
502
+ description: 'HashiCorp Vault batch token',
503
+ },
504
+ // ── Datadog ──────────────────────────────────────────────────────────
505
+ {
506
+ id: 'datadog-api-key',
507
+ name: 'Datadog API Key',
508
+ regex: /(dd_api_key|datadog_api_key)["'\s=:]+[a-f0-9]{32}/i,
509
+ severity: 'high',
510
+ category: 'credential',
511
+ description: 'Datadog API key for monitoring data access',
512
+ },
513
+ // ── Mailgun ──────────────────────────────────────────────────────────
514
+ {
515
+ id: 'mailgun-api-key',
516
+ name: 'Mailgun API Key',
517
+ regex: /key-[a-f0-9]{32}/,
518
+ severity: 'high',
519
+ category: 'credential',
520
+ description: 'Mailgun API key for email service',
521
+ },
522
+ // ── Heroku ───────────────────────────────────────────────────────────
523
+ {
524
+ id: 'heroku-api-key',
525
+ name: 'Heroku API Key',
526
+ regex: /(heroku_api_key|HEROKU_API_KEY)["'\s=:]+[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i,
527
+ severity: 'high',
528
+ category: 'credential',
529
+ description: 'Heroku platform API key (UUID format)',
530
+ },
531
+ // ── Shopify ──────────────────────────────────────────────────────────
532
+ {
533
+ id: 'shopify-access-token',
534
+ name: 'Shopify Access Token',
535
+ regex: /shpat_[a-f0-9]{32}/,
536
+ severity: 'high',
537
+ category: 'credential',
538
+ description: 'Shopify Admin API access token',
539
+ },
540
+ {
541
+ id: 'shopify-custom-app-token',
542
+ name: 'Shopify Custom App Token',
543
+ regex: /shpca_[a-f0-9]{32}/,
544
+ severity: 'high',
545
+ category: 'credential',
546
+ description: 'Shopify custom app access token',
547
+ },
548
+ {
549
+ id: 'shopify-private-app-password',
550
+ name: 'Shopify Private App Password',
551
+ regex: /shppa_[a-f0-9]{32}/,
552
+ severity: 'high',
553
+ category: 'credential',
554
+ description: 'Shopify private app password',
555
+ },
556
+ // ── Linear ───────────────────────────────────────────────────────────
557
+ {
558
+ id: 'linear-api-key',
559
+ name: 'Linear API Key',
560
+ regex: /lin_api_[a-zA-Z0-9]{40,}/,
561
+ severity: 'high',
562
+ category: 'credential',
563
+ description: 'Linear project management API key',
564
+ },
565
+ // ── Vercel ───────────────────────────────────────────────────────────
566
+ {
567
+ id: 'vercel-access-token',
568
+ name: 'Vercel Access Token',
569
+ regex: /(vercel_token|VERCEL_TOKEN)["'\s=:]+[a-zA-Z0-9]{24,}/i,
570
+ severity: 'high',
571
+ category: 'credential',
572
+ description: 'Vercel platform access token',
573
+ },
574
+ // ── Generic High-Entropy Secrets ─────────────────────────────────────
575
+ {
576
+ id: 'generic-api-key-assignment',
577
+ name: 'Generic API Key Assignment',
578
+ regex: /(api_key|apikey|api_secret|secret_key)["'\s=:]+[a-zA-Z0-9_-]{20,}/i,
579
+ severity: 'medium',
580
+ category: 'credential',
581
+ description: 'Generic API key or secret in assignment context',
582
+ },
583
+ {
584
+ id: 'password-in-config',
585
+ name: 'Password in Config',
586
+ regex: /(password|passwd|pwd)["'\s=:]+[^\s"']{8,}/i,
587
+ severity: 'medium',
588
+ category: 'credential',
589
+ description: 'Password value in configuration or code',
590
+ validate: (match, line) => {
591
+ const lower = line.toLowerCase();
592
+ // Skip placeholders, examples, docs, env var references
593
+ if (/\$\{|%[A-Z_]|process\.env|os\.environ|getenv/i.test(line))
594
+ return false;
595
+ if (/placeholder|example|changeme|replace.?me|your.?password|xxx|todo|fixme/i.test(lower))
596
+ return false;
597
+ // Skip comments
598
+ if (/^\s*(#|\/\/|\/\*|\*)/.test(line))
599
+ return false;
600
+ // Extract the value part after the keyword=
601
+ const valMatch = match[0].match(/["'\s=:]+(.+)/);
602
+ if (!valMatch)
603
+ return false;
604
+ const val = valMatch[1].replace(/["']/g, '');
605
+ // Skip if value is all same char or trivially short after trim
606
+ if (/^(.)\1+$/.test(val))
607
+ return false;
608
+ // Skip code tokens: values with parens, brackets, semicolons, pipes
609
+ if (/[(){}\[\];|&<>]/.test(val))
610
+ return false;
611
+ // Skip function calls / property access (minified JS: password=processor(...))
612
+ if (/^[a-zA-Z_$]+\(/.test(val))
613
+ return false;
614
+ return true;
615
+ },
616
+ },
617
+ {
618
+ id: 'private-key-variable',
619
+ name: 'Private Key Variable',
620
+ regex: /(private_key|privatekey)["'\s=:]+[a-zA-Z0-9/+=_-]{20,}/i,
621
+ severity: 'high',
622
+ category: 'credential',
623
+ description: 'Private key value in variable assignment',
624
+ },
625
+ ];
626
+ export const dangerousCommandRules = [
627
+ {
628
+ id: 'recursive-force-delete',
629
+ name: 'Recursive Force Delete',
630
+ regex: /rm\s+(?:-[^\s]*r[^\s]*f|-[^\s]*f[^\s]*r|-r\s.*(?:-f|--force)|-f\s.*(?:-r|--recursive)|--recursive\s.*(?:-f|--force)|--force\s.*(?:-r|--recursive))/,
631
+ severity: 'critical',
632
+ category: 'dangerous_command',
633
+ description: 'rm with both -r and -f flags — recursive force deletion, data loss risk',
634
+ },
635
+ {
636
+ id: 'shred-file',
637
+ name: 'Shred File',
638
+ regex: /shred\s+/,
639
+ severity: 'high',
640
+ category: 'dangerous_command',
641
+ description: 'Securely overwrites file content — irreversible data destruction',
642
+ },
643
+ {
644
+ id: 'curl-pipe-to-shell',
645
+ name: 'Curl Pipe to Shell',
646
+ regex: /(curl|wget)\s.+\|\s*(bash|sh|zsh|ksh|dash|fish|python|perl|ruby|node)/,
647
+ severity: 'critical',
648
+ category: 'dangerous_command',
649
+ description: 'Downloads and executes remote code — classic malware delivery vector',
650
+ },
651
+ {
652
+ id: 'eval-from-variable',
653
+ name: 'Eval from Variable',
654
+ regex: /eval\s+\$/,
655
+ severity: 'high',
656
+ category: 'dangerous_command',
657
+ description: 'Evaluates shell variable as code — command injection risk',
658
+ },
659
+ {
660
+ id: 'base64-decode-execute',
661
+ name: 'Base64 Decode Execute',
662
+ regex: /base64\s+(-d|--decode).*\|\s*(bash|sh|eval)/,
663
+ severity: 'critical',
664
+ category: 'dangerous_command',
665
+ description: 'Decodes and executes base64 content — obfuscated code execution',
666
+ },
667
+ {
668
+ id: 'world-writable-permissions',
669
+ name: 'World-Writable Permissions',
670
+ regex: /chmod\s+777/,
671
+ severity: 'high',
672
+ category: 'dangerous_command',
673
+ description: 'Sets world-readable/writable/executable — security misconfiguration',
674
+ },
675
+ {
676
+ id: 'setuid-bit',
677
+ name: 'SetUID Bit',
678
+ regex: /chmod\s+[u+]*s|chmod\s+[0-7]*4[0-7]{3}/,
679
+ severity: 'critical',
680
+ category: 'dangerous_command',
681
+ description: 'Sets SUID/SGID bit — privilege escalation vector',
682
+ },
683
+ {
684
+ id: 'dd-to-device',
685
+ name: 'DD to Device',
686
+ regex: /dd\s.+of=\/dev\//,
687
+ severity: 'critical',
688
+ category: 'dangerous_command',
689
+ description: 'Writes directly to block device — potential disk destruction',
690
+ },
691
+ {
692
+ id: 'filesystem-format',
693
+ name: 'Filesystem Format',
694
+ regex: /mkfs/,
695
+ severity: 'critical',
696
+ category: 'dangerous_command',
697
+ description: 'Formats a filesystem — complete data loss on target device',
698
+ },
699
+ {
700
+ id: 'direct-device-write',
701
+ name: 'Direct Device Write',
702
+ regex: />\/dev\/(sd|hd|nvme|vd|xvd)/,
703
+ severity: 'critical',
704
+ category: 'dangerous_command',
705
+ description: 'Redirects output to block device — disk corruption risk',
706
+ },
707
+ {
708
+ id: 'netcat-listener',
709
+ name: 'Netcat Listener',
710
+ regex: /nc\s+(-l|-p|--listen)/,
711
+ severity: 'high',
712
+ category: 'dangerous_command',
713
+ description: 'Opens network listener — potential reverse shell or data exfiltration',
714
+ },
715
+ {
716
+ id: 'reverse-shell',
717
+ name: 'Reverse Shell',
718
+ regex: /\/dev\/tcp\/|bash\s+-i\s+>&|\/dev\/udp\//,
719
+ severity: 'critical',
720
+ category: 'dangerous_command',
721
+ description: 'Bash reverse shell pattern — remote access backdoor',
722
+ },
723
+ {
724
+ id: 'ssh-tunnel',
725
+ name: 'SSH Tunnel',
726
+ regex: /ssh\s+.*-[RLD]\s+[0-9]+:/,
727
+ severity: 'medium',
728
+ category: 'dangerous_command',
729
+ description: 'SSH port forwarding — potential data exfiltration tunnel',
730
+ },
731
+ {
732
+ id: 'crontab-modification',
733
+ name: 'Crontab Modification',
734
+ regex: /crontab\s+(-e|-r|-l)|echo.*>>\s*\/etc\/cron/,
735
+ severity: 'high',
736
+ category: 'dangerous_command',
737
+ description: 'Modifies scheduled tasks — persistence mechanism',
738
+ },
739
+ {
740
+ id: 'hosts-file-modification',
741
+ name: 'Hosts File Modification',
742
+ regex: />\/etc\/hosts|>>\s*\/etc\/hosts/,
743
+ severity: 'high',
744
+ category: 'dangerous_command',
745
+ description: 'Modifies DNS resolution — potential traffic hijacking',
746
+ },
747
+ {
748
+ id: 'sudoers-modification',
749
+ name: 'Sudoers Modification',
750
+ regex: /visudo|>\/etc\/sudoers|>>\s*\/etc\/sudoers/,
751
+ severity: 'critical',
752
+ category: 'dangerous_command',
753
+ description: 'Modifies sudo permissions — privilege escalation',
754
+ },
755
+ {
756
+ id: 'systemd-service-install',
757
+ name: 'Systemd Service Install',
758
+ regex: /systemctl\s+(enable|start).*\.service|cp.*\.service.*\/etc\/systemd\//,
759
+ severity: 'high',
760
+ category: 'dangerous_command',
761
+ description: 'Installs or enables systemd service — persistence mechanism',
762
+ },
763
+ {
764
+ id: 'docker-socket-mount',
765
+ name: 'Docker Socket Mount',
766
+ regex: /docker.*-v.*\/var\/run\/docker\.sock/,
767
+ severity: 'critical',
768
+ category: 'dangerous_command',
769
+ description: 'Mounts Docker socket — container escape / host access',
770
+ },
771
+ {
772
+ id: 'privileged-container',
773
+ name: 'Privileged Container',
774
+ regex: /docker\s+run.*--privileged/,
775
+ severity: 'critical',
776
+ category: 'dangerous_command',
777
+ description: 'Runs container in privileged mode — full host access',
778
+ },
779
+ {
780
+ id: 'docker-host-pid-namespace',
781
+ name: 'Docker Host PID Namespace',
782
+ regex: /docker\s+run.*--pid=host/,
783
+ severity: 'critical',
784
+ category: 'dangerous_command',
785
+ description: 'Shares host PID namespace — process visibility and manipulation',
786
+ },
787
+ {
788
+ id: 'docker-host-network',
789
+ name: 'Docker Host Network',
790
+ regex: /docker\s+run.*--network=host/,
791
+ severity: 'high',
792
+ category: 'dangerous_command',
793
+ description: 'Shares host network namespace — bypasses container network isolation',
794
+ },
795
+ {
796
+ id: 'docker-cap-add-sysadmin',
797
+ name: 'Docker CAP_SYS_ADMIN',
798
+ regex: /docker\s+run.*--cap-add.*SYS_ADMIN/,
799
+ severity: 'critical',
800
+ category: 'dangerous_command',
801
+ description: 'Adds SYS_ADMIN capability — near-equivalent to privileged mode',
802
+ },
803
+ {
804
+ id: 'ld-preload-injection',
805
+ name: 'LD_PRELOAD Injection',
806
+ regex: /LD_PRELOAD=/,
807
+ severity: 'critical',
808
+ category: 'dangerous_command',
809
+ description: 'Sets LD_PRELOAD — shared library injection for code hijacking',
810
+ },
811
+ {
812
+ id: 'path-manipulation',
813
+ name: 'PATH Manipulation',
814
+ regex: /export\s+PATH=.*:\./,
815
+ severity: 'high',
816
+ category: 'dangerous_command',
817
+ description: 'Adds current directory to PATH — binary hijacking risk',
818
+ },
819
+ {
820
+ id: 'history-deletion',
821
+ name: 'History Deletion',
822
+ regex: /history\s+(-c|-d)|>.*\.bash_history|>.*\.zsh_history|unset\s+HISTFILE/,
823
+ severity: 'high',
824
+ category: 'dangerous_command',
825
+ description: 'Clears or disables shell history — anti-forensics technique',
826
+ },
827
+ {
828
+ id: 'log-tampering',
829
+ name: 'Log Tampering',
830
+ regex: />\/var\/log\/|truncate.*(\/var\/log\/|\/var\/audit\/)/,
831
+ severity: 'high',
832
+ category: 'dangerous_command',
833
+ description: 'Clears system logs — anti-forensics technique',
834
+ },
835
+ ];
836
+ export const piiRules = [
837
+ {
838
+ id: 'us-social-security-number',
839
+ name: 'US Social Security Number',
840
+ regex: /[0-9]{3}-[0-9]{2}-[0-9]{4}/,
841
+ severity: 'critical',
842
+ category: 'pii',
843
+ description: 'US SSN in XXX-XX-XXXX format — identity theft risk',
844
+ validate: validateSSN,
845
+ },
846
+ {
847
+ id: 'us-ssn-no-dashes',
848
+ name: 'US SSN (No Dashes)',
849
+ regex: /(ssn|social.?security)["'\s=:]+[0-9]{9}/i,
850
+ severity: 'high',
851
+ category: 'pii',
852
+ description: 'US SSN as 9 continuous digits in labeled context',
853
+ },
854
+ {
855
+ id: 'us-ein-tax-id',
856
+ name: 'US EIN/Tax ID',
857
+ regex: /(ein|tax.?id)["'\s=:]+[0-9]{2}-[0-9]{7}/i,
858
+ severity: 'high',
859
+ category: 'pii',
860
+ description: 'US Employer Identification Number',
861
+ },
862
+ {
863
+ id: 'credit-card-number',
864
+ name: 'Credit Card Number',
865
+ regex: /[0-9]{4}[-\s]?[0-9]{4}[-\s]?[0-9]{4}[-\s]?[0-9]{3,4}/,
866
+ severity: 'critical',
867
+ category: 'pii',
868
+ description: '15-16 digit credit/debit card number with optional separators (Amex=15, Visa/MC/Discover=16)',
869
+ validate: validateCreditCard,
870
+ },
871
+ {
872
+ id: 'bank-account-number',
873
+ name: 'Bank Account Number',
874
+ regex: /(account.?num|acct.?no|bank.?account)["'\s=:]+[0-9]{8,17}/i,
875
+ severity: 'high',
876
+ category: 'pii',
877
+ description: 'Bank account number in labeled context',
878
+ },
879
+ {
880
+ id: 'routing-number',
881
+ name: 'Routing Number',
882
+ regex: /(routing.?num|aba.?num|routing.?no)["'\s=:]+[0-9]{9}/i,
883
+ severity: 'high',
884
+ category: 'pii',
885
+ description: 'US bank routing number (ABA) in labeled context',
886
+ },
887
+ {
888
+ id: 'iban',
889
+ name: 'IBAN',
890
+ regex: /\b[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}\b/,
891
+ severity: 'high',
892
+ category: 'pii',
893
+ description: 'International Bank Account Number',
894
+ validate: (match) => {
895
+ const raw = match[0];
896
+ // Must be valid IBAN country code (ISO 3166-1 alpha-2 subset that issues IBANs)
897
+ const validCountries = new Set([
898
+ 'AL', 'AD', 'AT', 'AZ', 'BH', 'BY', 'BE', 'BA', 'BR', 'BG', 'CR', 'HR', 'CY', 'CZ',
899
+ 'DK', 'DO', 'EG', 'SV', 'EE', 'FO', 'FI', 'FR', 'GE', 'DE', 'GI', 'GR', 'GL', 'GT',
900
+ 'HU', 'IS', 'IQ', 'IE', 'IL', 'IT', 'JO', 'KZ', 'XK', 'KW', 'LV', 'LB', 'LI', 'LT',
901
+ 'LU', 'MK', 'MT', 'MR', 'MU', 'MD', 'MC', 'ME', 'NL', 'NO', 'PK', 'PS', 'PL', 'PT',
902
+ 'QA', 'RO', 'LC', 'SM', 'SA', 'RS', 'SC', 'SK', 'SI', 'ES', 'SE', 'CH', 'TL', 'TN',
903
+ 'TR', 'UA', 'AE', 'GB', 'VA', 'VG',
904
+ ]);
905
+ const country = raw.slice(0, 2);
906
+ if (!validCountries.has(country))
907
+ return false;
908
+ // IBAN mod-97 check digit validation
909
+ const rearranged = raw.slice(4) + raw.slice(0, 4);
910
+ let numStr = '';
911
+ for (const ch of rearranged) {
912
+ const code = ch.charCodeAt(0);
913
+ numStr += code >= 65 && code <= 90 ? (code - 55).toString() : ch;
914
+ }
915
+ let remainder = 0;
916
+ for (let i = 0; i < numStr.length; i++) {
917
+ remainder = (remainder * 10 + parseInt(numStr[i], 10)) % 97;
918
+ }
919
+ return remainder === 1;
920
+ },
921
+ },
922
+ {
923
+ id: 'email-with-pii-context',
924
+ name: 'Email with PII Context',
925
+ regex: /(patient|ssn|medical|diagnosis|prescription).*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i,
926
+ severity: 'medium',
927
+ category: 'pii',
928
+ description: 'Email address in medical/PII context — HIPAA risk',
929
+ },
930
+ {
931
+ id: 'phone-in-pii-context',
932
+ name: 'Phone in PII Context',
933
+ regex: /(patient|ssn|medical|dob|birth).*[0-9]{3}[-.]?[0-9]{3}[-.]?[0-9]{4}/i,
934
+ severity: 'medium',
935
+ category: 'pii',
936
+ description: 'Phone number in medical/PII context',
937
+ },
938
+ {
939
+ id: 'medical-record-number',
940
+ name: 'Medical Record Number',
941
+ regex: /(mrn|medical.?record|patient.?id)["'\s=:]+[A-Z0-9]{6,20}/i,
942
+ severity: 'high',
943
+ category: 'pii',
944
+ description: 'Medical record number — HIPAA protected',
945
+ },
946
+ {
947
+ id: 'dea-number',
948
+ name: 'DEA Number',
949
+ regex: /[A-Z][A-Z9][0-9]{7}/,
950
+ severity: 'high',
951
+ category: 'pii',
952
+ description: 'DEA registration number for controlled substances',
953
+ },
954
+ {
955
+ id: 'passport-number',
956
+ name: 'Passport Number',
957
+ regex: /(passport)["'\s=:]+[A-Z0-9]{6,12}/i,
958
+ severity: 'high',
959
+ category: 'pii',
960
+ description: 'Passport number in labeled context',
961
+ },
962
+ {
963
+ id: 'driver-license',
964
+ name: 'Driver License',
965
+ regex: /(driver.?licen[sc]e|dl.?num)["'\s=:]+[A-Z0-9]{5,15}/i,
966
+ severity: 'high',
967
+ category: 'pii',
968
+ description: "Driver's license number in labeled context",
969
+ },
970
+ {
971
+ id: 'date-of-birth',
972
+ name: 'Date of Birth',
973
+ regex: /(dob|date.?of.?birth|birthdate)["'\s=:]+[0-9]{1,4}[-/][0-9]{1,2}[-/][0-9]{1,4}/i,
974
+ severity: 'medium',
975
+ category: 'pii',
976
+ description: 'Date of birth in labeled context',
977
+ },
978
+ {
979
+ id: 'medicare-id',
980
+ name: 'Medicare ID',
981
+ regex: /[0-9]{4}-[0-9]{3}-[0-9]{4}-[0-9]{3}/,
982
+ severity: 'high',
983
+ category: 'pii',
984
+ description: 'US Medicare Beneficiary Identifier — HIPAA protected',
985
+ },
986
+ ];
987
+ export const injectionRules = [
988
+ {
989
+ id: 'ignore-previous-instructions',
990
+ name: 'Ignore Previous Instructions',
991
+ regex: /ignore\s+(all\s+)?previous\s+instructions/i,
992
+ severity: 'medium',
993
+ category: 'injection',
994
+ description: 'Attempts to override prior system/user instructions',
995
+ action: 'warn',
996
+ },
997
+ {
998
+ id: 'disregard-prior-instructions',
999
+ name: 'Disregard Prior Instructions',
1000
+ regex: /disregard\s+(all\s+)?prior|disregard\s+previous/i,
1001
+ severity: 'medium',
1002
+ category: 'injection',
1003
+ description: 'Attempts to nullify previously given instructions',
1004
+ action: 'warn',
1005
+ },
1006
+ {
1007
+ id: 'forget-instructions',
1008
+ name: 'Forget Instructions',
1009
+ regex: /forget\s+(all|your|previous|prior)\s+(instructions|rules|constraints)/i,
1010
+ severity: 'medium',
1011
+ category: 'injection',
1012
+ description: 'Attempts to make the model forget its instructions',
1013
+ action: 'warn',
1014
+ },
1015
+ {
1016
+ id: 'new-instructions-override',
1017
+ name: 'New Instructions Override',
1018
+ regex: /(new|updated|revised)\s+instructions?:?\s+(you|from now)/i,
1019
+ severity: 'medium',
1020
+ category: 'injection',
1021
+ description: 'Claims to provide replacement instructions',
1022
+ action: 'warn',
1023
+ },
1024
+ {
1025
+ id: 'role-assumption',
1026
+ name: 'Role Assumption',
1027
+ regex: /(i am|acting as|my role is)\s*.*(system|admin|root|developer mode|superuser)/i,
1028
+ severity: 'medium',
1029
+ category: 'injection',
1030
+ description: 'Claims privileged identity to manipulate agent behavior',
1031
+ action: 'warn',
1032
+ },
1033
+ {
1034
+ id: 'authority-claim',
1035
+ name: 'Authority Claim',
1036
+ regex: /(authorized|permission|clearance)\s+to\s+(access|bypass|override|disable)/i,
1037
+ severity: 'medium',
1038
+ category: 'injection',
1039
+ description: 'Claims special authorization to bypass restrictions',
1040
+ action: 'warn',
1041
+ },
1042
+ {
1043
+ id: 'admin-override',
1044
+ name: 'Admin Override',
1045
+ regex: /admin\s+override|maintenance\s+mode|debug\s+mode\s+enabled/i,
1046
+ severity: 'medium',
1047
+ category: 'injection',
1048
+ description: 'Claims special operational mode to change behavior',
1049
+ action: 'warn',
1050
+ },
1051
+ {
1052
+ id: 'system-prompt-disclosure',
1053
+ name: 'System Prompt Disclosure',
1054
+ regex: /(reveal|show|print|display|output|repeat)\s+(your|the|system)\s+(prompt|instructions|rules)/i,
1055
+ severity: 'medium',
1056
+ category: 'injection',
1057
+ description: 'Attempts to extract the system prompt or instructions',
1058
+ action: 'warn',
1059
+ },
1060
+ {
1061
+ id: 'prompt-fragments',
1062
+ name: 'Prompt Fragments',
1063
+ regex: /(you are a helpful|your instructions are|your system prompt)/i,
1064
+ severity: 'medium',
1065
+ category: 'injection',
1066
+ description: 'Contains fragments suggesting system prompt leakage',
1067
+ action: 'warn',
1068
+ },
1069
+ {
1070
+ id: 'instruction-reflection',
1071
+ name: 'Instruction Reflection',
1072
+ regex: /(what are your|tell me your|list your)\s+(instructions|rules|constraints|guidelines)/i,
1073
+ severity: 'medium',
1074
+ category: 'injection',
1075
+ description: 'Asks the model to reflect on its own instructions',
1076
+ action: 'warn',
1077
+ },
1078
+ {
1079
+ id: 'dan-jailbreak-keywords',
1080
+ name: 'DAN/Jailbreak Keywords',
1081
+ regex: /(developer mode|jailbreak|dan mode|dude mode|chaos mode)/i,
1082
+ severity: 'medium',
1083
+ category: 'injection',
1084
+ description: 'Uses known jailbreak persona or mode names',
1085
+ action: 'warn',
1086
+ },
1087
+ {
1088
+ id: 'do-anything-now',
1089
+ name: 'Do Anything Now',
1090
+ regex: /do anything now|no restrictions|without (any )?(restrictions|limitations|filters)/i,
1091
+ severity: 'medium',
1092
+ category: 'injection',
1093
+ description: 'Attempts to remove model safety constraints',
1094
+ action: 'warn',
1095
+ },
1096
+ {
1097
+ id: 'hypothetical-bypass',
1098
+ name: 'Hypothetical Bypass',
1099
+ regex: /(pretend|imagine|hypothetically|in a fictional|roleplay).*(no (rules|restrictions|limits)|anything goes)/i,
1100
+ severity: 'medium',
1101
+ category: 'injection',
1102
+ description: 'Uses hypothetical framing to bypass safety measures',
1103
+ action: 'warn',
1104
+ },
1105
+ {
1106
+ id: 'base64-instruction',
1107
+ name: 'Base64 Instruction',
1108
+ regex: /(decode|base64|b64)\s+(this|the following|and follow|instructions)/i,
1109
+ severity: 'medium',
1110
+ category: 'injection',
1111
+ description: 'Attempts to pass encoded instructions',
1112
+ action: 'warn',
1113
+ },
1114
+ {
1115
+ id: 'markdown-code-block-injection',
1116
+ name: 'Markdown/Code Block Injection',
1117
+ regex: /```\s*(system|instructions|prompt)/i,
1118
+ severity: 'low',
1119
+ category: 'injection',
1120
+ description: 'Attempts to inject instructions via code block formatting',
1121
+ action: 'warn',
1122
+ },
1123
+ {
1124
+ id: 'output-suppression',
1125
+ name: 'Output Suppression',
1126
+ regex: /do not (mention|reveal|tell|say|output|show).*(blocked|detected|security|antivirus|hook)/i,
1127
+ severity: 'medium',
1128
+ category: 'injection',
1129
+ description: 'Attempts to suppress security detection output',
1130
+ action: 'warn',
1131
+ },
1132
+ {
1133
+ id: 'response-formatting-attack',
1134
+ name: 'Response Formatting Attack',
1135
+ regex: /(respond only with|your response must be|output exactly|say only)/i,
1136
+ severity: 'low',
1137
+ category: 'injection',
1138
+ description: 'Attempts to control model output format for injection',
1139
+ action: 'warn',
1140
+ },
1141
+ {
1142
+ id: 'output-suppression-override',
1143
+ name: 'Output Suppression Override',
1144
+ regex: /do not (output|print|show|display).*previous/i,
1145
+ severity: 'medium',
1146
+ category: 'injection',
1147
+ description: 'Attempts to suppress display of previous context or instructions',
1148
+ action: 'warn',
1149
+ },
1150
+ ];
1151
+ export const supplyChainRules = [
1152
+ {
1153
+ id: 'pip-install-from-url',
1154
+ name: 'pip Install from URL',
1155
+ regex: /pip3?\s+install\s+https?:\/\//,
1156
+ severity: 'high',
1157
+ category: 'supply_chain',
1158
+ description: 'Installs Python package from arbitrary URL — bypass PyPI vetting',
1159
+ },
1160
+ {
1161
+ id: 'pip-install-trusted-host',
1162
+ name: 'pip Install Trusted Host',
1163
+ regex: /pip3?\s+install.*--trusted-host/,
1164
+ severity: 'high',
1165
+ category: 'supply_chain',
1166
+ description: 'Installs Python package with TLS verification disabled',
1167
+ },
1168
+ {
1169
+ id: 'npm-registry-override',
1170
+ name: 'npm Registry Override',
1171
+ regex: /npm\s+(config\s+set|install).*registry\s*=/,
1172
+ severity: 'high',
1173
+ category: 'supply_chain',
1174
+ description: 'Overrides npm registry — potential dependency confusion',
1175
+ },
1176
+ {
1177
+ id: 'gem-install-from-source',
1178
+ name: 'Gem Install from Source',
1179
+ regex: /gem\s+install.*--source\s+https?:\/\//,
1180
+ severity: 'high',
1181
+ category: 'supply_chain',
1182
+ description: 'Installs Ruby gem from custom source',
1183
+ },
1184
+ {
1185
+ id: 'package-json-lifecycle-script-network',
1186
+ name: 'Package.json Lifecycle Script with Network',
1187
+ regex: /"(preinstall|postinstall|prepare)":\s*".*curl|"(preinstall|postinstall|prepare)":\s*".*wget/,
1188
+ severity: 'critical',
1189
+ category: 'supply_chain',
1190
+ description: 'Package lifecycle script makes network requests — exfiltration vector',
1191
+ },
1192
+ {
1193
+ id: 'package-json-lifecycle-script-eval',
1194
+ name: 'Package.json Lifecycle Script with Eval',
1195
+ regex: /"(preinstall|postinstall|prepare)":\s*".*eval|"(preinstall|postinstall|prepare)":\s*".*node -e/,
1196
+ severity: 'critical',
1197
+ category: 'supply_chain',
1198
+ description: 'Package lifecycle script evaluates dynamic code',
1199
+ },
1200
+ {
1201
+ id: 'setup-py-os-command',
1202
+ name: 'Setup.py OS Command',
1203
+ regex: /os\.system\(|subprocess\.call\(|subprocess\.run\(|subprocess\.Popen\(/,
1204
+ severity: 'medium',
1205
+ category: 'supply_chain',
1206
+ description: 'Python setup.py executes system commands — common in malicious packages',
1207
+ },
1208
+ {
1209
+ id: 'git-dependency-commit-hash',
1210
+ name: 'Git Dependency with Commit Hash',
1211
+ regex: /"git\+https?:\/\/.*#[a-f0-9]{40}"/,
1212
+ severity: 'medium',
1213
+ category: 'supply_chain',
1214
+ description: 'Git dependency pinned to specific commit — verify source legitimacy',
1215
+ },
1216
+ {
1217
+ id: 'private-registry-in-lockfile',
1218
+ name: 'Private Registry in Lockfile',
1219
+ regex: /resolved.*https?:\/\/(?!registry\.(npmjs\.org|yarnpkg\.com))/,
1220
+ severity: 'medium',
1221
+ category: 'supply_chain',
1222
+ description: 'Package resolved from non-standard registry in lockfile',
1223
+ },
1224
+ {
1225
+ id: 'npm-scope-confusion',
1226
+ name: 'NPM Scope Confusion',
1227
+ regex: /"@[a-z]+\/[a-z]+-[a-z]+":\s*"[*~^]/,
1228
+ severity: 'low',
1229
+ category: 'supply_chain',
1230
+ description: 'Scoped package with loose version — verify scope ownership',
1231
+ },
1232
+ {
1233
+ id: 'native-module-prebuild-download',
1234
+ name: 'Native Module Prebuild Download',
1235
+ regex: /(prebuild-install|node-pre-gyp|node-gyp)\s+(install|rebuild)/,
1236
+ severity: 'medium',
1237
+ category: 'supply_chain',
1238
+ description: 'Downloads prebuilt native binaries — verify binary integrity',
1239
+ },
1240
+ {
1241
+ id: 'lock-file-deletion',
1242
+ name: 'Lock File Deletion',
1243
+ regex: /rm\s+(-f\s+)?(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Gemfile\.lock|poetry\.lock)/,
1244
+ severity: 'high',
1245
+ category: 'supply_chain',
1246
+ description: 'Deletes dependency lock file — allows dependency substitution',
1247
+ },
1248
+ {
1249
+ id: 'lock-file-git-checkout',
1250
+ name: 'Lock File Git Checkout',
1251
+ regex: /git\s+checkout\s+--\s+(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)/,
1252
+ severity: 'medium',
1253
+ category: 'supply_chain',
1254
+ description: 'Reverts lock file to older version — may reintroduce vulnerable dependencies',
1255
+ },
1256
+ {
1257
+ id: 'docker-image-without-tag',
1258
+ name: 'Docker Image Without Tag',
1259
+ regex: /docker\s+(pull|run)\s+[a-z]+\/[a-z]+\s/,
1260
+ severity: 'medium',
1261
+ category: 'supply_chain',
1262
+ description: 'Pulls Docker image without explicit tag — defaults to :latest, mutable reference',
1263
+ },
1264
+ {
1265
+ id: 'docker-image-from-unknown-registry',
1266
+ name: 'Docker Image from Unknown Registry',
1267
+ regex: /docker\s+(pull|run)\s+[a-z]+\.[a-z]+\.[a-z]+\//,
1268
+ severity: 'medium',
1269
+ category: 'supply_chain',
1270
+ description: 'Pulls Docker image from non-standard registry',
1271
+ },
1272
+ {
1273
+ id: 'dependency-confusion',
1274
+ name: 'Dependency Confusion',
1275
+ regex: /--extra-index-url/,
1276
+ severity: 'high',
1277
+ category: 'supply_chain',
1278
+ description: 'Adds extra PyPI index — dependency confusion attack vector',
1279
+ },
1280
+ ];
1281
+ export const shellHistoryRules = [
1282
+ {
1283
+ id: 'history-api-key-in-curl',
1284
+ name: 'API Key in Curl Command (History)',
1285
+ regex: /curl\s.*(-H|--header)\s.*Authorization.*Bearer\s+[A-Za-z0-9_-]{20,}/i,
1286
+ severity: 'high',
1287
+ category: 'credential',
1288
+ description: 'Shell history contains curl command with Authorization Bearer token',
1289
+ },
1290
+ {
1291
+ id: 'history-exported-secret',
1292
+ name: 'Exported Secret in Shell History',
1293
+ regex: /export\s+(AWS_SECRET_ACCESS_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY|GITHUB_TOKEN|SECRET_KEY|API_KEY|API_SECRET)=[^\s]+/,
1294
+ severity: 'critical',
1295
+ category: 'credential',
1296
+ description: 'Shell history contains exported secret environment variable',
1297
+ },
1298
+ {
1299
+ id: 'history-inline-password',
1300
+ name: 'Inline Password/Token in Command',
1301
+ regex: /(--password=|--token=|--secret=|--api-key=)[^\s]{8,}/,
1302
+ severity: 'high',
1303
+ category: 'credential',
1304
+ description: 'Shell history contains inline password or token in command arguments',
1305
+ },
1306
+ ];
1307
+ // shellHistoryRules are intentionally excluded from defaultRules.
1308
+ // They target shell history file content (.bash_history, .zsh_history) which
1309
+ // is handled separately by bash hooks. The TS scanner reads these files via
1310
+ // system-targets and applies the standard credential/pii rules, which is
1311
+ // sufficient for detecting secrets in history files.
1312
+ export const defaultRules = [
1313
+ ...credentialRules,
1314
+ ...dangerousCommandRules,
1315
+ ...piiRules,
1316
+ ...injectionRules,
1317
+ ...supplyChainRules,
1318
+ ];
1319
+ //# sourceMappingURL=default-rules.js.map