@trailofbits/vsix-audit 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 (197) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +281 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +703 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +4 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/scanner/batch.d.ts +12 -0
  12. package/dist/scanner/batch.d.ts.map +1 -0
  13. package/dist/scanner/batch.js +104 -0
  14. package/dist/scanner/batch.js.map +1 -0
  15. package/dist/scanner/bundler.d.ts +35 -0
  16. package/dist/scanner/bundler.d.ts.map +1 -0
  17. package/dist/scanner/bundler.js +120 -0
  18. package/dist/scanner/bundler.js.map +1 -0
  19. package/dist/scanner/cache.d.ts +45 -0
  20. package/dist/scanner/cache.d.ts.map +1 -0
  21. package/dist/scanner/cache.js +153 -0
  22. package/dist/scanner/cache.js.map +1 -0
  23. package/dist/scanner/cache.test.d.ts +2 -0
  24. package/dist/scanner/cache.test.d.ts.map +1 -0
  25. package/dist/scanner/cache.test.js +149 -0
  26. package/dist/scanner/cache.test.js.map +1 -0
  27. package/dist/scanner/capabilities.d.ts +29 -0
  28. package/dist/scanner/capabilities.d.ts.map +1 -0
  29. package/dist/scanner/capabilities.js +217 -0
  30. package/dist/scanner/capabilities.js.map +1 -0
  31. package/dist/scanner/checks/ast.d.ts +3 -0
  32. package/dist/scanner/checks/ast.d.ts.map +1 -0
  33. package/dist/scanner/checks/ast.js +469 -0
  34. package/dist/scanner/checks/ast.js.map +1 -0
  35. package/dist/scanner/checks/ast.test.d.ts +2 -0
  36. package/dist/scanner/checks/ast.test.d.ts.map +1 -0
  37. package/dist/scanner/checks/ast.test.js +389 -0
  38. package/dist/scanner/checks/ast.test.js.map +1 -0
  39. package/dist/scanner/checks/behavioral.d.ts +3 -0
  40. package/dist/scanner/checks/behavioral.d.ts.map +1 -0
  41. package/dist/scanner/checks/behavioral.js +367 -0
  42. package/dist/scanner/checks/behavioral.js.map +1 -0
  43. package/dist/scanner/checks/blocklist.d.ts +3 -0
  44. package/dist/scanner/checks/blocklist.d.ts.map +1 -0
  45. package/dist/scanner/checks/blocklist.js +32 -0
  46. package/dist/scanner/checks/blocklist.js.map +1 -0
  47. package/dist/scanner/checks/blocklist.test.d.ts +2 -0
  48. package/dist/scanner/checks/blocklist.test.d.ts.map +1 -0
  49. package/dist/scanner/checks/blocklist.test.js +74 -0
  50. package/dist/scanner/checks/blocklist.test.js.map +1 -0
  51. package/dist/scanner/checks/chains.d.ts +35 -0
  52. package/dist/scanner/checks/chains.d.ts.map +1 -0
  53. package/dist/scanner/checks/chains.js +505 -0
  54. package/dist/scanner/checks/chains.js.map +1 -0
  55. package/dist/scanner/checks/chains.test.d.ts +2 -0
  56. package/dist/scanner/checks/chains.test.d.ts.map +1 -0
  57. package/dist/scanner/checks/chains.test.js +250 -0
  58. package/dist/scanner/checks/chains.test.js.map +1 -0
  59. package/dist/scanner/checks/dataflow.d.ts +3 -0
  60. package/dist/scanner/checks/dataflow.d.ts.map +1 -0
  61. package/dist/scanner/checks/dataflow.js +316 -0
  62. package/dist/scanner/checks/dataflow.js.map +1 -0
  63. package/dist/scanner/checks/dependencies.d.ts +13 -0
  64. package/dist/scanner/checks/dependencies.d.ts.map +1 -0
  65. package/dist/scanner/checks/dependencies.js +225 -0
  66. package/dist/scanner/checks/dependencies.js.map +1 -0
  67. package/dist/scanner/checks/dependencies.test.d.ts +2 -0
  68. package/dist/scanner/checks/dependencies.test.d.ts.map +1 -0
  69. package/dist/scanner/checks/dependencies.test.js +248 -0
  70. package/dist/scanner/checks/dependencies.test.js.map +1 -0
  71. package/dist/scanner/checks/finding-quality.test.d.ts +8 -0
  72. package/dist/scanner/checks/finding-quality.test.d.ts.map +1 -0
  73. package/dist/scanner/checks/finding-quality.test.js +164 -0
  74. package/dist/scanner/checks/finding-quality.test.js.map +1 -0
  75. package/dist/scanner/checks/ioc.d.ts +20 -0
  76. package/dist/scanner/checks/ioc.d.ts.map +1 -0
  77. package/dist/scanner/checks/ioc.js +234 -0
  78. package/dist/scanner/checks/ioc.js.map +1 -0
  79. package/dist/scanner/checks/ioc.test.d.ts +2 -0
  80. package/dist/scanner/checks/ioc.test.d.ts.map +1 -0
  81. package/dist/scanner/checks/ioc.test.js +298 -0
  82. package/dist/scanner/checks/ioc.test.js.map +1 -0
  83. package/dist/scanner/checks/manifest.d.ts +6 -0
  84. package/dist/scanner/checks/manifest.d.ts.map +1 -0
  85. package/dist/scanner/checks/manifest.js +123 -0
  86. package/dist/scanner/checks/manifest.js.map +1 -0
  87. package/dist/scanner/checks/manifest.test.d.ts +2 -0
  88. package/dist/scanner/checks/manifest.test.d.ts.map +1 -0
  89. package/dist/scanner/checks/manifest.test.js +108 -0
  90. package/dist/scanner/checks/manifest.test.js.map +1 -0
  91. package/dist/scanner/checks/obfuscation.d.ts +3 -0
  92. package/dist/scanner/checks/obfuscation.d.ts.map +1 -0
  93. package/dist/scanner/checks/obfuscation.js +432 -0
  94. package/dist/scanner/checks/obfuscation.js.map +1 -0
  95. package/dist/scanner/checks/obfuscation.test.d.ts +2 -0
  96. package/dist/scanner/checks/obfuscation.test.d.ts.map +1 -0
  97. package/dist/scanner/checks/obfuscation.test.js +399 -0
  98. package/dist/scanner/checks/obfuscation.test.js.map +1 -0
  99. package/dist/scanner/checks/package.d.ts +17 -0
  100. package/dist/scanner/checks/package.d.ts.map +1 -0
  101. package/dist/scanner/checks/package.js +422 -0
  102. package/dist/scanner/checks/package.js.map +1 -0
  103. package/dist/scanner/checks/package.test.d.ts +2 -0
  104. package/dist/scanner/checks/package.test.d.ts.map +1 -0
  105. package/dist/scanner/checks/package.test.js +518 -0
  106. package/dist/scanner/checks/package.test.js.map +1 -0
  107. package/dist/scanner/checks/patterns.d.ts +5 -0
  108. package/dist/scanner/checks/patterns.d.ts.map +1 -0
  109. package/dist/scanner/checks/patterns.js +251 -0
  110. package/dist/scanner/checks/patterns.js.map +1 -0
  111. package/dist/scanner/checks/patterns.test.d.ts +2 -0
  112. package/dist/scanner/checks/patterns.test.d.ts.map +1 -0
  113. package/dist/scanner/checks/patterns.test.js +147 -0
  114. package/dist/scanner/checks/patterns.test.js.map +1 -0
  115. package/dist/scanner/checks/unicode.d.ts +3 -0
  116. package/dist/scanner/checks/unicode.d.ts.map +1 -0
  117. package/dist/scanner/checks/unicode.js +247 -0
  118. package/dist/scanner/checks/unicode.js.map +1 -0
  119. package/dist/scanner/checks/unicode.test.d.ts +2 -0
  120. package/dist/scanner/checks/unicode.test.d.ts.map +1 -0
  121. package/dist/scanner/checks/unicode.test.js +202 -0
  122. package/dist/scanner/checks/unicode.test.js.map +1 -0
  123. package/dist/scanner/checks/yara.d.ts +23 -0
  124. package/dist/scanner/checks/yara.d.ts.map +1 -0
  125. package/dist/scanner/checks/yara.js +349 -0
  126. package/dist/scanner/checks/yara.js.map +1 -0
  127. package/dist/scanner/checks/yara.test.d.ts +2 -0
  128. package/dist/scanner/checks/yara.test.d.ts.map +1 -0
  129. package/dist/scanner/checks/yara.test.js +126 -0
  130. package/dist/scanner/checks/yara.test.js.map +1 -0
  131. package/dist/scanner/constants.d.ts +18 -0
  132. package/dist/scanner/constants.d.ts.map +1 -0
  133. package/dist/scanner/constants.js +37 -0
  134. package/dist/scanner/constants.js.map +1 -0
  135. package/dist/scanner/detection-coverage.test.d.ts +2 -0
  136. package/dist/scanner/detection-coverage.test.d.ts.map +1 -0
  137. package/dist/scanner/detection-coverage.test.js +216 -0
  138. package/dist/scanner/detection-coverage.test.js.map +1 -0
  139. package/dist/scanner/download.d.ts +76 -0
  140. package/dist/scanner/download.d.ts.map +1 -0
  141. package/dist/scanner/download.js +339 -0
  142. package/dist/scanner/download.js.map +1 -0
  143. package/dist/scanner/download.test.d.ts +2 -0
  144. package/dist/scanner/download.test.d.ts.map +1 -0
  145. package/dist/scanner/download.test.js +149 -0
  146. package/dist/scanner/download.test.js.map +1 -0
  147. package/dist/scanner/index.d.ts +8 -0
  148. package/dist/scanner/index.d.ts.map +1 -0
  149. package/dist/scanner/index.js +167 -0
  150. package/dist/scanner/index.js.map +1 -0
  151. package/dist/scanner/index.test.d.ts +2 -0
  152. package/dist/scanner/index.test.d.ts.map +1 -0
  153. package/dist/scanner/index.test.js +71 -0
  154. package/dist/scanner/index.test.js.map +1 -0
  155. package/dist/scanner/loaders/zoo.d.ts +3 -0
  156. package/dist/scanner/loaders/zoo.d.ts.map +1 -0
  157. package/dist/scanner/loaders/zoo.js +112 -0
  158. package/dist/scanner/loaders/zoo.js.map +1 -0
  159. package/dist/scanner/types.d.ts +118 -0
  160. package/dist/scanner/types.d.ts.map +1 -0
  161. package/dist/scanner/types.js +2 -0
  162. package/dist/scanner/types.js.map +1 -0
  163. package/dist/scanner/utils.d.ts +14 -0
  164. package/dist/scanner/utils.d.ts.map +1 -0
  165. package/dist/scanner/utils.js +25 -0
  166. package/dist/scanner/utils.js.map +1 -0
  167. package/dist/scanner/vsix.d.ts +6 -0
  168. package/dist/scanner/vsix.d.ts.map +1 -0
  169. package/dist/scanner/vsix.js +213 -0
  170. package/dist/scanner/vsix.js.map +1 -0
  171. package/dist/scanner/vsix.test.d.ts +2 -0
  172. package/dist/scanner/vsix.test.d.ts.map +1 -0
  173. package/dist/scanner/vsix.test.js +355 -0
  174. package/dist/scanner/vsix.test.js.map +1 -0
  175. package/package.json +60 -0
  176. package/zoo/blocklist/extensions.json +201 -0
  177. package/zoo/iocs/blockchain-extensions.txt +21 -0
  178. package/zoo/iocs/c2-domains.txt +50 -0
  179. package/zoo/iocs/c2-ips.txt +24 -0
  180. package/zoo/iocs/hashes.txt +47 -0
  181. package/zoo/iocs/malicious-npm.txt +85 -0
  182. package/zoo/iocs/wallets.txt +18 -0
  183. package/zoo/signatures/yara/README.md +46 -0
  184. package/zoo/signatures/yara/blockchain_c2.yar +48 -0
  185. package/zoo/signatures/yara/code_execution.yar +165 -0
  186. package/zoo/signatures/yara/credential_harvesting.yar +116 -0
  187. package/zoo/signatures/yara/crypto_wallet_targeting.yar +92 -0
  188. package/zoo/signatures/yara/data_exfiltration.yar +207 -0
  189. package/zoo/signatures/yara/google_calendar_c2.yar +187 -0
  190. package/zoo/signatures/yara/messaging_c2.yar +103 -0
  191. package/zoo/signatures/yara/multi_stage_attacks.yar +331 -0
  192. package/zoo/signatures/yara/obfuscation_patterns.yar +208 -0
  193. package/zoo/signatures/yara/powershell_attacks.yar +116 -0
  194. package/zoo/signatures/yara/rat_capabilities.yar +243 -0
  195. package/zoo/signatures/yara/self_propagation.yar +239 -0
  196. package/zoo/signatures/yara/unicode_stealth.yar +48 -0
  197. package/zoo/signatures/yara/websocket_c2.yar +83 -0
@@ -0,0 +1,505 @@
1
+ import { isScannable, SCANNABLE_EXTENSIONS_PATTERN } from "../constants.js";
2
+ import { findLineNumberByIndex } from "../utils.js";
3
+ // =============================================================================
4
+ // Stage Definitions (sources, sinks, and behavioral actions)
5
+ // =============================================================================
6
+ const STAGES = {
7
+ // Sources (where sensitive data originates)
8
+ SSH_KEYS: {
9
+ id: "SSH_KEYS",
10
+ name: "SSH private keys",
11
+ patterns: [
12
+ /\.ssh\/id_(?:rsa|ed25519|ecdsa|dsa)/gi,
13
+ /\.ssh\/config/gi,
14
+ /BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY/gi,
15
+ /BEGIN\s+OPENSSH\s+PRIVATE\s+KEY/gi,
16
+ /(?:fs|promises?)\.readFile(?:Sync)?\s*\([^)]*\.ssh/gi,
17
+ /readFile(?:Sync)?\s*\([^)]*id_(?:rsa|ed25519)/gi,
18
+ ],
19
+ },
20
+ CRYPTO_WALLETS: {
21
+ id: "CRYPTO_WALLETS",
22
+ name: "Cryptocurrency wallets",
23
+ patterns: [
24
+ /\.ethereum/gi,
25
+ /\.bitcoin/gi,
26
+ /wallet\.dat/gi,
27
+ /keystore\/[a-z0-9-]+/gi,
28
+ /solana\/id\.json/gi,
29
+ /Exodus/gi,
30
+ /MetaMask/gi,
31
+ /phantom/gi,
32
+ /readFile(?:Sync)?\s*\([^)]*(?:wallet|ethereum|bitcoin|keystore)/gi,
33
+ /readFile(?:Sync)?\s*\([^)]*\.solana/gi,
34
+ /seed.*phrase/gi,
35
+ /mnemonic/gi,
36
+ ],
37
+ },
38
+ CREDENTIALS: {
39
+ id: "CREDENTIALS",
40
+ name: "Credential files",
41
+ patterns: [
42
+ /\.env(?:\.local|\.production)?/gi,
43
+ /\.npmrc/gi,
44
+ /\.netrc/gi,
45
+ /\.git-credentials/gi,
46
+ /credentials\.json/gi,
47
+ /secrets?\./gi,
48
+ /readFile(?:Sync)?\s*\([^)]*\.env/gi,
49
+ /readFile(?:Sync)?\s*\([^)]*\.npmrc/gi,
50
+ /process\.env\.[A-Z_]+(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)/gi,
51
+ ],
52
+ },
53
+ BROWSER_DATA: {
54
+ id: "BROWSER_DATA",
55
+ name: "Browser stored data",
56
+ patterns: [
57
+ /Google[/\\]Chrome[/\\].*Login\s+Data/gi,
58
+ /Google[/\\]Chrome[/\\].*Cookies/gi,
59
+ /Mozilla[/\\]Firefox[/\\].*logins\.json/gi,
60
+ /BraveSoftware[/\\].*Login\s+Data/gi,
61
+ /Microsoft[/\\]Edge[/\\].*Login\s+Data/gi,
62
+ /Local\s+Storage[/\\]leveldb/gi,
63
+ /readFile(?:Sync)?\s*\([^)]*(?:Chrome|Firefox|Edge|Brave)/gi,
64
+ /readFile(?:Sync)?\s*\([^)]*Login\s*Data/gi,
65
+ ],
66
+ },
67
+ API_TOKENS: {
68
+ id: "API_TOKENS",
69
+ name: "API tokens and keys",
70
+ patterns: [
71
+ /(?:GITHUB|GITLAB|BITBUCKET)_(?:TOKEN|API_KEY)/gi,
72
+ /NPM_TOKEN/gi,
73
+ /OPENVSX_(?:TOKEN|PAT)/gi,
74
+ /(?:AWS|AZURE|GCP)_(?:ACCESS_KEY|SECRET|TOKEN)/gi,
75
+ /OPENAI_API_KEY/gi,
76
+ /ANTHROPIC_API_KEY/gi,
77
+ /process\.env\.(?:GITHUB|GITLAB|NPM|AWS|AZURE|OPENAI|ANTHROPIC)/gi,
78
+ ],
79
+ },
80
+ // Sinks (where data leaves or gets executed)
81
+ NETWORK_SEND: {
82
+ id: "NETWORK_SEND",
83
+ name: "Network transmission",
84
+ patterns: [
85
+ /fetch\s*\([^)]*,\s*\{[^}]*method\s*:\s*['"](?:POST|PUT)/gi,
86
+ /axios\.(?:post|put)\s*\(/gi,
87
+ /https?\.request\s*\([^)]*method\s*:\s*['"](?:POST|PUT)/gi,
88
+ /request\.(?:post|put)\s*\(/gi,
89
+ /got\.(?:post|put)\s*\(/gi,
90
+ /superagent\.(?:post|put)\s*\(/gi,
91
+ ],
92
+ },
93
+ WEBSOCKET_SEND: {
94
+ id: "WEBSOCKET_SEND",
95
+ name: "WebSocket transmission",
96
+ patterns: [/\.send\s*\([^)]+\)/gi, /WebSocket\s*\([^)]*\)/gi, /ws\.send\s*\(/gi],
97
+ },
98
+ DISCORD_WEBHOOK: {
99
+ id: "DISCORD_WEBHOOK",
100
+ name: "Discord webhook",
101
+ patterns: [/discord\.com\/api\/webhooks/gi, /discordapp\.com\/api\/webhooks/gi],
102
+ },
103
+ EVAL_EXEC: {
104
+ id: "EVAL_EXEC",
105
+ name: "Code execution",
106
+ patterns: [
107
+ /\beval\s*\(/gi,
108
+ /new\s+Function\s*\(/gi,
109
+ /\(\s*\)\s*\[\s*['"]constructor['"]\s*\]/gi,
110
+ ],
111
+ },
112
+ CHILD_PROCESS: {
113
+ id: "CHILD_PROCESS",
114
+ name: "Shell execution",
115
+ patterns: [
116
+ /child_process\.(?:exec|execSync|spawn|spawnSync)\s*\(/gi,
117
+ /(?:exec|execSync|spawn|spawnSync)\s*\([^)]*\$\{/gi,
118
+ ],
119
+ },
120
+ // Behavioral stages
121
+ FILE_READ: {
122
+ id: "FILE_READ",
123
+ name: "File read operation",
124
+ patterns: [/readFile(?:Sync)?\s*\(/gi, /fs\.promises\.readFile/gi, /createReadStream\s*\(/gi],
125
+ },
126
+ FILE_WRITE: {
127
+ id: "FILE_WRITE",
128
+ name: "File write operation",
129
+ patterns: [
130
+ /writeFile(?:Sync)?\s*\(/gi,
131
+ /createWriteStream\s*\(/gi,
132
+ /fs\.promises\.writeFile/gi,
133
+ /appendFile/gi,
134
+ ],
135
+ },
136
+ ENCODE: {
137
+ id: "ENCODE",
138
+ name: "Data encoding",
139
+ patterns: [
140
+ /Buffer\.from\s*\([^)]+\)\.toString\s*\(\s*['"]base64/gi,
141
+ /btoa\s*\(/gi,
142
+ /\.toString\s*\(\s*['"](?:base64|hex)['"]\s*\)/gi,
143
+ /JSON\.stringify\s*\(/gi,
144
+ ],
145
+ },
146
+ NETWORK: {
147
+ id: "NETWORK",
148
+ name: "Network activity",
149
+ patterns: [
150
+ /fetch\s*\(/gi,
151
+ /axios\./gi,
152
+ /https?\.request/gi,
153
+ /\.post\s*\(/gi,
154
+ /\.send\s*\(/gi,
155
+ /net\.Socket/gi,
156
+ /net\.connect/gi,
157
+ /net\.createConnection/gi,
158
+ /new\s+WebSocket/gi,
159
+ ],
160
+ },
161
+ EXEC: {
162
+ id: "EXEC",
163
+ name: "Command execution",
164
+ patterns: [
165
+ /child_process/gi,
166
+ /\.spawn\s*\(/gi,
167
+ /\.exec\s*\(/gi,
168
+ /process\.stdin/gi,
169
+ /execSync/gi,
170
+ /spawnSync/gi,
171
+ ],
172
+ },
173
+ ENV_ACCESS: {
174
+ id: "ENV_ACCESS",
175
+ name: "Environment access",
176
+ patterns: [
177
+ /os\.homedir\s*\(\)/gi,
178
+ /os\.userInfo\s*\(\)/gi,
179
+ /process\.env\.(?:HOME|USERPROFILE|APPDATA)/gi,
180
+ ],
181
+ },
182
+ DOWNLOAD: {
183
+ id: "DOWNLOAD",
184
+ name: "Remote download",
185
+ patterns: [
186
+ /fetch\s*\([^)]*https?:\/\//gi,
187
+ /axios\.get\s*\([^)]*https?:\/\//gi,
188
+ /https?\.get\s*\(/gi,
189
+ /request\s*\([^)]*https?:\/\//gi,
190
+ /curl\s+/gi,
191
+ /wget\s+/gi,
192
+ ],
193
+ },
194
+ CLIPBOARD: {
195
+ id: "CLIPBOARD",
196
+ name: "Keystroke/clipboard capture",
197
+ patterns: [
198
+ /keyboard.*event/gi,
199
+ /keydown|keyup|keypress/gi,
200
+ /clipboard\.readText/gi,
201
+ /getSelection\s*\(\s*\)\.toString/gi,
202
+ ],
203
+ },
204
+ PERSISTENCE: {
205
+ id: "PERSISTENCE",
206
+ name: "Persistence storage",
207
+ patterns: [
208
+ /globalState\.update/gi,
209
+ /writeFileSync?\s*\([^)]*keystroke/gi,
210
+ /localStorage\.setItem/gi,
211
+ ],
212
+ },
213
+ STARTUP_FILE: {
214
+ id: "STARTUP_FILE",
215
+ name: "Startup file access",
216
+ patterns: [/\.bashrc/gi, /\.zshrc/gi, /\.profile/gi, /crontab/gi, /startup/gi, /autostart/gi],
217
+ },
218
+ PUBLISH_CREDS: {
219
+ id: "PUBLISH_CREDS",
220
+ name: "Publishing credentials",
221
+ patterns: [/\.npmrc/gi, /NPM_TOKEN/gi, /OPENVSX_TOKEN/gi, /npm\s+config/gi],
222
+ },
223
+ PUBLISH_CMD: {
224
+ id: "PUBLISH_CMD",
225
+ name: "Package publishing",
226
+ patterns: [/npm\s+publish/gi, /vsce\s+publish/gi, /ovsx\s+publish/gi, /yarn\s+publish/gi],
227
+ },
228
+ };
229
+ // =============================================================================
230
+ // Chain Rules (combining stages into detection patterns)
231
+ // =============================================================================
232
+ const CHAIN_RULES = [
233
+ // DataFlow-style rules (2-stage: source → sink)
234
+ {
235
+ id: "FLOW_SSH_KEY_EXFIL",
236
+ title: "SSH key exfiltration pattern",
237
+ description: "Code reads SSH private keys and sends data over network. This is a credential theft pattern.",
238
+ severity: "critical",
239
+ stages: [STAGES["SSH_KEYS"], STAGES["NETWORK_SEND"]],
240
+ constraints: { maxSpan: 2000 },
241
+ redFlags: ["Reads .ssh directory", "Sends to external URL"],
242
+ },
243
+ {
244
+ id: "FLOW_WALLET_EXFIL",
245
+ title: "Cryptocurrency wallet exfiltration",
246
+ description: "Code accesses cryptocurrency wallet data and sends it over network. This is a crypto theft pattern.",
247
+ severity: "critical",
248
+ stages: [STAGES["CRYPTO_WALLETS"], STAGES["NETWORK_SEND"]],
249
+ constraints: { maxSpan: 2000 },
250
+ redFlags: ["Accesses wallet files", "Sends to external server"],
251
+ },
252
+ {
253
+ id: "FLOW_CRED_EXFIL",
254
+ title: "Credential exfiltration pattern",
255
+ description: "Code reads credential files (.env, .npmrc, etc.) and sends data over network.",
256
+ severity: "critical",
257
+ stages: [STAGES["CREDENTIALS"], STAGES["NETWORK_SEND"]],
258
+ constraints: { maxSpan: 2000 },
259
+ redFlags: ["Reads environment files", "HTTP POST to external"],
260
+ },
261
+ {
262
+ id: "FLOW_BROWSER_EXFIL",
263
+ title: "Browser data exfiltration",
264
+ description: "Code accesses browser stored passwords/cookies and sends them over network.",
265
+ severity: "critical",
266
+ stages: [STAGES["BROWSER_DATA"], STAGES["NETWORK_SEND"]],
267
+ constraints: { maxSpan: 2000 },
268
+ redFlags: ["Reads Chrome/Firefox data", "Network exfiltration"],
269
+ },
270
+ {
271
+ id: "FLOW_TOKEN_EXFIL",
272
+ title: "API token exfiltration",
273
+ description: "Code accesses API tokens from environment and sends them to external server.",
274
+ severity: "critical",
275
+ stages: [STAGES["API_TOKENS"], STAGES["NETWORK_SEND"]],
276
+ constraints: { maxSpan: 2000 },
277
+ legitimateUses: ["Token validation services", "OAuth flows"],
278
+ redFlags: ["Tokens sent to unknown domains", "No user consent"],
279
+ },
280
+ {
281
+ id: "FLOW_SSH_DISCORD",
282
+ title: "SSH key sent to Discord",
283
+ description: "Code reads SSH keys and sends them to Discord webhook. This is a common exfiltration technique.",
284
+ severity: "critical",
285
+ stages: [STAGES["SSH_KEYS"], STAGES["DISCORD_WEBHOOK"]],
286
+ constraints: { maxSpan: 2000 },
287
+ },
288
+ {
289
+ id: "FLOW_CRED_DISCORD",
290
+ title: "Credentials sent to Discord",
291
+ description: "Code reads credentials and sends them to Discord webhook for exfiltration.",
292
+ severity: "critical",
293
+ stages: [STAGES["CREDENTIALS"], STAGES["DISCORD_WEBHOOK"]],
294
+ constraints: { maxSpan: 2000 },
295
+ },
296
+ {
297
+ id: "FLOW_SSH_EXEC",
298
+ title: "SSH key used in command execution",
299
+ description: "SSH key content is passed to command execution, potentially for remote access.",
300
+ severity: "high",
301
+ stages: [STAGES["SSH_KEYS"], STAGES["CHILD_PROCESS"]],
302
+ constraints: { maxSpan: 2000 },
303
+ legitimateUses: ["SSH key management tools", "Git operations"],
304
+ redFlags: ["Key content passed to exec", "Unknown remote commands"],
305
+ },
306
+ // Behavioral-style rules (N-stage attack chains)
307
+ {
308
+ id: "BEHAVIOR_CREDENTIAL_EXFIL",
309
+ title: "Credential exfiltration pattern",
310
+ description: "Code reads sensitive files, encodes the content, and sends it to an external server. This is the classic credential theft attack chain.",
311
+ severity: "critical",
312
+ stages: [STAGES["FILE_READ"], STAGES["ENCODE"], STAGES["NETWORK"]],
313
+ constraints: { maxSpan: 3000 },
314
+ redFlags: [
315
+ "Reads from home directory or .ssh",
316
+ "Encodes before sending",
317
+ "Sends to external domain",
318
+ ],
319
+ },
320
+ {
321
+ id: "BEHAVIOR_REVERSE_SHELL",
322
+ title: "Reverse shell pattern",
323
+ description: "Code establishes network connection and pipes input to command execution. This creates a remote shell for attackers.",
324
+ severity: "critical",
325
+ stages: [STAGES["NETWORK"], STAGES["EXEC"]],
326
+ constraints: { maxSpan: 1500 },
327
+ redFlags: ["Socket piped to shell", "Remote command execution"],
328
+ },
329
+ {
330
+ id: "BEHAVIOR_SUPPLY_CHAIN_ATTACK",
331
+ title: "Install script attack pattern",
332
+ description: "Package lifecycle script accesses environment, executes commands, and phones home. This is a supply chain attack pattern.",
333
+ severity: "high",
334
+ stages: [STAGES["ENV_ACCESS"], STAGES["EXEC"], STAGES["NETWORK"]],
335
+ constraints: { minStages: 3, maxSpan: 1000 },
336
+ legitimateUses: ["Build scripts", "Development tools"],
337
+ redFlags: ["Runs in postinstall", "Collects system info", "Sends to unknown domain"],
338
+ },
339
+ {
340
+ id: "BEHAVIOR_DROPPER",
341
+ title: "Malware dropper pattern",
342
+ description: "Code downloads content from remote URL, writes it to file, and executes it. This is a dropper/downloader pattern.",
343
+ severity: "critical",
344
+ stages: [STAGES["DOWNLOAD"], STAGES["FILE_WRITE"], STAGES["EXEC"]],
345
+ constraints: { maxSpan: 2000 },
346
+ redFlags: [
347
+ "Downloads executable",
348
+ "Writes to temp or hidden location",
349
+ "Executes downloaded content",
350
+ ],
351
+ },
352
+ {
353
+ id: "BEHAVIOR_KEYLOGGER",
354
+ title: "Keystroke capture pattern",
355
+ description: "Code captures keyboard/input events and stores or transmits the data. This indicates keylogging behavior.",
356
+ severity: "high",
357
+ stages: [STAGES["CLIPBOARD"], STAGES["PERSISTENCE"], STAGES["DISCORD_WEBHOOK"]],
358
+ constraints: { minStages: 2, maxSpan: 3000 },
359
+ legitimateUses: ["Keyboard shortcut extensions"],
360
+ redFlags: ["Captures all keystrokes", "Sends to Discord webhook", "No user consent mechanism"],
361
+ },
362
+ {
363
+ id: "BEHAVIOR_CRYPTO_STEALER",
364
+ title: "Cryptocurrency stealer pattern",
365
+ description: "Code scans for wallet files, extracts keys/seeds, and exfiltrates them.",
366
+ severity: "critical",
367
+ stages: [STAGES["CRYPTO_WALLETS"], STAGES["ENCODE"], STAGES["DISCORD_WEBHOOK"]],
368
+ constraints: { minStages: 3, maxSpan: 1500 },
369
+ redFlags: [
370
+ "Scans for multiple wallet types",
371
+ "Extracts private keys",
372
+ "Sends to Discord/external",
373
+ ],
374
+ },
375
+ {
376
+ id: "BEHAVIOR_PERSISTENCE",
377
+ title: "Persistence mechanism pattern",
378
+ description: "Code modifies startup files, schedules tasks, or installs itself for persistence.",
379
+ severity: "high",
380
+ stages: [STAGES["STARTUP_FILE"], STAGES["FILE_WRITE"]],
381
+ constraints: { maxSpan: 2000 },
382
+ legitimateUses: ["Shell configuration tools", "Development environment setup"],
383
+ redFlags: ["Writes to startup files", "Adds hidden entries", "No user interaction"],
384
+ },
385
+ {
386
+ id: "BEHAVIOR_SELF_PROPAGATION",
387
+ title: "Self-propagation pattern",
388
+ description: "Code accesses package publishing credentials and attempts to publish itself. This is worm-like behavior.",
389
+ severity: "critical",
390
+ stages: [STAGES["PUBLISH_CREDS"], STAGES["PUBLISH_CMD"]],
391
+ constraints: { maxSpan: 2000 },
392
+ redFlags: ["Accesses publish tokens", "Runs publish commands", "GlassWorm-style worm"],
393
+ },
394
+ ];
395
+ // =============================================================================
396
+ // Core Detection Logic
397
+ // =============================================================================
398
+ /**
399
+ * Find all matches for a set of patterns in content.
400
+ */
401
+ function findMatches(content, patterns) {
402
+ const matches = [];
403
+ for (const pattern of patterns) {
404
+ const regex = new RegExp(pattern.source, pattern.flags);
405
+ let match;
406
+ while ((match = regex.exec(content)) !== null) {
407
+ matches.push({
408
+ index: match.index,
409
+ matched: match[0].slice(0, 80),
410
+ });
411
+ }
412
+ }
413
+ return matches;
414
+ }
415
+ /**
416
+ * Check if a chain rule matches in the content.
417
+ * Returns array of stage matches if rule triggers, null otherwise.
418
+ */
419
+ function checkRule(content, rule) {
420
+ const stageMatches = [];
421
+ const minStages = rule.constraints.minStages ?? rule.stages.length;
422
+ const maxSpan = rule.constraints.maxSpan ?? 3000;
423
+ // Find matches for each stage
424
+ for (const stage of rule.stages) {
425
+ const matches = findMatches(content, stage.patterns);
426
+ if (matches.length > 0) {
427
+ const firstMatch = matches[0];
428
+ if (firstMatch) {
429
+ stageMatches.push({
430
+ stageId: stage.id,
431
+ stageName: stage.name,
432
+ index: firstMatch.index,
433
+ matched: firstMatch.matched,
434
+ });
435
+ }
436
+ }
437
+ }
438
+ // Check if enough stages matched
439
+ if (stageMatches.length < minStages) {
440
+ return null;
441
+ }
442
+ // Check if stages are within maxSpan
443
+ if (stageMatches.length > 1) {
444
+ const indices = stageMatches.map((m) => m.index);
445
+ const span = Math.max(...indices) - Math.min(...indices);
446
+ if (span > maxSpan) {
447
+ return null;
448
+ }
449
+ }
450
+ return stageMatches;
451
+ }
452
+ // =============================================================================
453
+ // Main Export
454
+ // =============================================================================
455
+ export function checkChains(contents) {
456
+ const findings = [];
457
+ const seenFindings = new Set();
458
+ for (const [filename, buffer] of contents.files) {
459
+ if (!isScannable(filename, SCANNABLE_EXTENSIONS_PATTERN))
460
+ continue;
461
+ const content = buffer.toString("utf8");
462
+ for (const rule of CHAIN_RULES) {
463
+ const stageMatches = checkRule(content, rule);
464
+ if (!stageMatches)
465
+ continue;
466
+ // Deduplicate
467
+ const key = `${rule.id}:${filename}`;
468
+ if (seenFindings.has(key))
469
+ continue;
470
+ seenFindings.add(key);
471
+ const firstMatch = stageMatches[0];
472
+ if (!firstMatch)
473
+ continue;
474
+ // Determine category based on rule ID prefix
475
+ const category = rule.id.startsWith("FLOW_") ? "dataflow" : "behavioral";
476
+ findings.push({
477
+ id: rule.id,
478
+ title: rule.title,
479
+ description: rule.description,
480
+ severity: rule.severity,
481
+ category,
482
+ location: {
483
+ file: filename,
484
+ line: findLineNumberByIndex(content, firstMatch.index),
485
+ },
486
+ metadata: {
487
+ stagesMatched: stageMatches.length,
488
+ totalStages: rule.stages.length,
489
+ stages: stageMatches.map((m) => ({
490
+ id: m.stageId,
491
+ name: m.stageName,
492
+ matched: m.matched,
493
+ line: findLineNumberByIndex(content, m.index),
494
+ })),
495
+ ...(rule.legitimateUses && { legitimateUses: rule.legitimateUses }),
496
+ ...(rule.redFlags && { redFlags: rule.redFlags }),
497
+ },
498
+ });
499
+ }
500
+ }
501
+ return findings;
502
+ }
503
+ // Export for testing
504
+ export { CHAIN_RULES, STAGES };
505
+ //# sourceMappingURL=chains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chains.js","sourceRoot":"","sources":["../../../src/scanner/checks/chains.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chains.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chains.test.d.ts","sourceRoot":"","sources":["../../../src/scanner/checks/chains.test.ts"],"names":[],"mappings":""}