@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.
- package/LICENSE +661 -0
- package/README.md +281 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +703 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/batch.d.ts +12 -0
- package/dist/scanner/batch.d.ts.map +1 -0
- package/dist/scanner/batch.js +104 -0
- package/dist/scanner/batch.js.map +1 -0
- package/dist/scanner/bundler.d.ts +35 -0
- package/dist/scanner/bundler.d.ts.map +1 -0
- package/dist/scanner/bundler.js +120 -0
- package/dist/scanner/bundler.js.map +1 -0
- package/dist/scanner/cache.d.ts +45 -0
- package/dist/scanner/cache.d.ts.map +1 -0
- package/dist/scanner/cache.js +153 -0
- package/dist/scanner/cache.js.map +1 -0
- package/dist/scanner/cache.test.d.ts +2 -0
- package/dist/scanner/cache.test.d.ts.map +1 -0
- package/dist/scanner/cache.test.js +149 -0
- package/dist/scanner/cache.test.js.map +1 -0
- package/dist/scanner/capabilities.d.ts +29 -0
- package/dist/scanner/capabilities.d.ts.map +1 -0
- package/dist/scanner/capabilities.js +217 -0
- package/dist/scanner/capabilities.js.map +1 -0
- package/dist/scanner/checks/ast.d.ts +3 -0
- package/dist/scanner/checks/ast.d.ts.map +1 -0
- package/dist/scanner/checks/ast.js +469 -0
- package/dist/scanner/checks/ast.js.map +1 -0
- package/dist/scanner/checks/ast.test.d.ts +2 -0
- package/dist/scanner/checks/ast.test.d.ts.map +1 -0
- package/dist/scanner/checks/ast.test.js +389 -0
- package/dist/scanner/checks/ast.test.js.map +1 -0
- package/dist/scanner/checks/behavioral.d.ts +3 -0
- package/dist/scanner/checks/behavioral.d.ts.map +1 -0
- package/dist/scanner/checks/behavioral.js +367 -0
- package/dist/scanner/checks/behavioral.js.map +1 -0
- package/dist/scanner/checks/blocklist.d.ts +3 -0
- package/dist/scanner/checks/blocklist.d.ts.map +1 -0
- package/dist/scanner/checks/blocklist.js +32 -0
- package/dist/scanner/checks/blocklist.js.map +1 -0
- package/dist/scanner/checks/blocklist.test.d.ts +2 -0
- package/dist/scanner/checks/blocklist.test.d.ts.map +1 -0
- package/dist/scanner/checks/blocklist.test.js +74 -0
- package/dist/scanner/checks/blocklist.test.js.map +1 -0
- package/dist/scanner/checks/chains.d.ts +35 -0
- package/dist/scanner/checks/chains.d.ts.map +1 -0
- package/dist/scanner/checks/chains.js +505 -0
- package/dist/scanner/checks/chains.js.map +1 -0
- package/dist/scanner/checks/chains.test.d.ts +2 -0
- package/dist/scanner/checks/chains.test.d.ts.map +1 -0
- package/dist/scanner/checks/chains.test.js +250 -0
- package/dist/scanner/checks/chains.test.js.map +1 -0
- package/dist/scanner/checks/dataflow.d.ts +3 -0
- package/dist/scanner/checks/dataflow.d.ts.map +1 -0
- package/dist/scanner/checks/dataflow.js +316 -0
- package/dist/scanner/checks/dataflow.js.map +1 -0
- package/dist/scanner/checks/dependencies.d.ts +13 -0
- package/dist/scanner/checks/dependencies.d.ts.map +1 -0
- package/dist/scanner/checks/dependencies.js +225 -0
- package/dist/scanner/checks/dependencies.js.map +1 -0
- package/dist/scanner/checks/dependencies.test.d.ts +2 -0
- package/dist/scanner/checks/dependencies.test.d.ts.map +1 -0
- package/dist/scanner/checks/dependencies.test.js +248 -0
- package/dist/scanner/checks/dependencies.test.js.map +1 -0
- package/dist/scanner/checks/finding-quality.test.d.ts +8 -0
- package/dist/scanner/checks/finding-quality.test.d.ts.map +1 -0
- package/dist/scanner/checks/finding-quality.test.js +164 -0
- package/dist/scanner/checks/finding-quality.test.js.map +1 -0
- package/dist/scanner/checks/ioc.d.ts +20 -0
- package/dist/scanner/checks/ioc.d.ts.map +1 -0
- package/dist/scanner/checks/ioc.js +234 -0
- package/dist/scanner/checks/ioc.js.map +1 -0
- package/dist/scanner/checks/ioc.test.d.ts +2 -0
- package/dist/scanner/checks/ioc.test.d.ts.map +1 -0
- package/dist/scanner/checks/ioc.test.js +298 -0
- package/dist/scanner/checks/ioc.test.js.map +1 -0
- package/dist/scanner/checks/manifest.d.ts +6 -0
- package/dist/scanner/checks/manifest.d.ts.map +1 -0
- package/dist/scanner/checks/manifest.js +123 -0
- package/dist/scanner/checks/manifest.js.map +1 -0
- package/dist/scanner/checks/manifest.test.d.ts +2 -0
- package/dist/scanner/checks/manifest.test.d.ts.map +1 -0
- package/dist/scanner/checks/manifest.test.js +108 -0
- package/dist/scanner/checks/manifest.test.js.map +1 -0
- package/dist/scanner/checks/obfuscation.d.ts +3 -0
- package/dist/scanner/checks/obfuscation.d.ts.map +1 -0
- package/dist/scanner/checks/obfuscation.js +432 -0
- package/dist/scanner/checks/obfuscation.js.map +1 -0
- package/dist/scanner/checks/obfuscation.test.d.ts +2 -0
- package/dist/scanner/checks/obfuscation.test.d.ts.map +1 -0
- package/dist/scanner/checks/obfuscation.test.js +399 -0
- package/dist/scanner/checks/obfuscation.test.js.map +1 -0
- package/dist/scanner/checks/package.d.ts +17 -0
- package/dist/scanner/checks/package.d.ts.map +1 -0
- package/dist/scanner/checks/package.js +422 -0
- package/dist/scanner/checks/package.js.map +1 -0
- package/dist/scanner/checks/package.test.d.ts +2 -0
- package/dist/scanner/checks/package.test.d.ts.map +1 -0
- package/dist/scanner/checks/package.test.js +518 -0
- package/dist/scanner/checks/package.test.js.map +1 -0
- package/dist/scanner/checks/patterns.d.ts +5 -0
- package/dist/scanner/checks/patterns.d.ts.map +1 -0
- package/dist/scanner/checks/patterns.js +251 -0
- package/dist/scanner/checks/patterns.js.map +1 -0
- package/dist/scanner/checks/patterns.test.d.ts +2 -0
- package/dist/scanner/checks/patterns.test.d.ts.map +1 -0
- package/dist/scanner/checks/patterns.test.js +147 -0
- package/dist/scanner/checks/patterns.test.js.map +1 -0
- package/dist/scanner/checks/unicode.d.ts +3 -0
- package/dist/scanner/checks/unicode.d.ts.map +1 -0
- package/dist/scanner/checks/unicode.js +247 -0
- package/dist/scanner/checks/unicode.js.map +1 -0
- package/dist/scanner/checks/unicode.test.d.ts +2 -0
- package/dist/scanner/checks/unicode.test.d.ts.map +1 -0
- package/dist/scanner/checks/unicode.test.js +202 -0
- package/dist/scanner/checks/unicode.test.js.map +1 -0
- package/dist/scanner/checks/yara.d.ts +23 -0
- package/dist/scanner/checks/yara.d.ts.map +1 -0
- package/dist/scanner/checks/yara.js +349 -0
- package/dist/scanner/checks/yara.js.map +1 -0
- package/dist/scanner/checks/yara.test.d.ts +2 -0
- package/dist/scanner/checks/yara.test.d.ts.map +1 -0
- package/dist/scanner/checks/yara.test.js +126 -0
- package/dist/scanner/checks/yara.test.js.map +1 -0
- package/dist/scanner/constants.d.ts +18 -0
- package/dist/scanner/constants.d.ts.map +1 -0
- package/dist/scanner/constants.js +37 -0
- package/dist/scanner/constants.js.map +1 -0
- package/dist/scanner/detection-coverage.test.d.ts +2 -0
- package/dist/scanner/detection-coverage.test.d.ts.map +1 -0
- package/dist/scanner/detection-coverage.test.js +216 -0
- package/dist/scanner/detection-coverage.test.js.map +1 -0
- package/dist/scanner/download.d.ts +76 -0
- package/dist/scanner/download.d.ts.map +1 -0
- package/dist/scanner/download.js +339 -0
- package/dist/scanner/download.js.map +1 -0
- package/dist/scanner/download.test.d.ts +2 -0
- package/dist/scanner/download.test.d.ts.map +1 -0
- package/dist/scanner/download.test.js +149 -0
- package/dist/scanner/download.test.js.map +1 -0
- package/dist/scanner/index.d.ts +8 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +167 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/index.test.d.ts +2 -0
- package/dist/scanner/index.test.d.ts.map +1 -0
- package/dist/scanner/index.test.js +71 -0
- package/dist/scanner/index.test.js.map +1 -0
- package/dist/scanner/loaders/zoo.d.ts +3 -0
- package/dist/scanner/loaders/zoo.d.ts.map +1 -0
- package/dist/scanner/loaders/zoo.js +112 -0
- package/dist/scanner/loaders/zoo.js.map +1 -0
- package/dist/scanner/types.d.ts +118 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +2 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/scanner/utils.d.ts +14 -0
- package/dist/scanner/utils.d.ts.map +1 -0
- package/dist/scanner/utils.js +25 -0
- package/dist/scanner/utils.js.map +1 -0
- package/dist/scanner/vsix.d.ts +6 -0
- package/dist/scanner/vsix.d.ts.map +1 -0
- package/dist/scanner/vsix.js +213 -0
- package/dist/scanner/vsix.js.map +1 -0
- package/dist/scanner/vsix.test.d.ts +2 -0
- package/dist/scanner/vsix.test.d.ts.map +1 -0
- package/dist/scanner/vsix.test.js +355 -0
- package/dist/scanner/vsix.test.js.map +1 -0
- package/package.json +60 -0
- package/zoo/blocklist/extensions.json +201 -0
- package/zoo/iocs/blockchain-extensions.txt +21 -0
- package/zoo/iocs/c2-domains.txt +50 -0
- package/zoo/iocs/c2-ips.txt +24 -0
- package/zoo/iocs/hashes.txt +47 -0
- package/zoo/iocs/malicious-npm.txt +85 -0
- package/zoo/iocs/wallets.txt +18 -0
- package/zoo/signatures/yara/README.md +46 -0
- package/zoo/signatures/yara/blockchain_c2.yar +48 -0
- package/zoo/signatures/yara/code_execution.yar +165 -0
- package/zoo/signatures/yara/credential_harvesting.yar +116 -0
- package/zoo/signatures/yara/crypto_wallet_targeting.yar +92 -0
- package/zoo/signatures/yara/data_exfiltration.yar +207 -0
- package/zoo/signatures/yara/google_calendar_c2.yar +187 -0
- package/zoo/signatures/yara/messaging_c2.yar +103 -0
- package/zoo/signatures/yara/multi_stage_attacks.yar +331 -0
- package/zoo/signatures/yara/obfuscation_patterns.yar +208 -0
- package/zoo/signatures/yara/powershell_attacks.yar +116 -0
- package/zoo/signatures/yara/rat_capabilities.yar +243 -0
- package/zoo/signatures/yara/self_propagation.yar +239 -0
- package/zoo/signatures/yara/unicode_stealth.yar +48 -0
- package/zoo/signatures/yara/websocket_c2.yar +83 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { access, readdir, writeFile, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
/**
|
|
8
|
+
* Binary file extensions that should be skipped for YARA scanning.
|
|
9
|
+
* These cause false positives because YARA pattern matching on binary
|
|
10
|
+
* content often matches arbitrary byte sequences.
|
|
11
|
+
*/
|
|
12
|
+
const BINARY_EXTENSIONS = new Set([
|
|
13
|
+
// Java
|
|
14
|
+
".jar",
|
|
15
|
+
".class",
|
|
16
|
+
".war",
|
|
17
|
+
".ear",
|
|
18
|
+
// Compiled
|
|
19
|
+
".wasm",
|
|
20
|
+
".pyc",
|
|
21
|
+
".pyo",
|
|
22
|
+
// Images
|
|
23
|
+
".png",
|
|
24
|
+
".jpg",
|
|
25
|
+
".jpeg",
|
|
26
|
+
".gif",
|
|
27
|
+
".bmp",
|
|
28
|
+
".ico",
|
|
29
|
+
".webp",
|
|
30
|
+
".svg",
|
|
31
|
+
".tiff",
|
|
32
|
+
".tif",
|
|
33
|
+
// Fonts
|
|
34
|
+
".ttf",
|
|
35
|
+
".otf",
|
|
36
|
+
".woff",
|
|
37
|
+
".woff2",
|
|
38
|
+
".eot",
|
|
39
|
+
// Audio/Video
|
|
40
|
+
".mp3",
|
|
41
|
+
".mp4",
|
|
42
|
+
".wav",
|
|
43
|
+
".ogg",
|
|
44
|
+
".webm",
|
|
45
|
+
".avi",
|
|
46
|
+
// Archives
|
|
47
|
+
".zip",
|
|
48
|
+
".tar",
|
|
49
|
+
".gz",
|
|
50
|
+
".bz2",
|
|
51
|
+
".xz",
|
|
52
|
+
".7z",
|
|
53
|
+
".rar",
|
|
54
|
+
// Documents
|
|
55
|
+
".pdf",
|
|
56
|
+
// Native binaries (scanned separately by checkNativeFiles)
|
|
57
|
+
".node",
|
|
58
|
+
".dll",
|
|
59
|
+
".dylib",
|
|
60
|
+
".so",
|
|
61
|
+
".exe",
|
|
62
|
+
// Other binary
|
|
63
|
+
".bin",
|
|
64
|
+
".dat",
|
|
65
|
+
]);
|
|
66
|
+
/**
|
|
67
|
+
* Check if a file should be skipped for YARA scanning
|
|
68
|
+
*/
|
|
69
|
+
function shouldSkipForYara(filename) {
|
|
70
|
+
const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase();
|
|
71
|
+
return BINARY_EXTENSIONS.has(ext);
|
|
72
|
+
}
|
|
73
|
+
const execFileAsync = promisify(execFile);
|
|
74
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
75
|
+
/**
|
|
76
|
+
* Find the YARA rules directory, checking multiple locations.
|
|
77
|
+
* Priority:
|
|
78
|
+
* 1. VSIX_AUDIT_ZOO_PATH environment variable + /signatures/yara
|
|
79
|
+
* 2. Development: ../../../zoo/signatures/yara relative to module
|
|
80
|
+
* 3. Installed: ../../zoo/signatures/yara relative to dist
|
|
81
|
+
*/
|
|
82
|
+
async function findYaraRulesDir() {
|
|
83
|
+
// Check environment variable first
|
|
84
|
+
const envPath = process.env["VSIX_AUDIT_ZOO_PATH"];
|
|
85
|
+
if (envPath) {
|
|
86
|
+
return join(envPath, "signatures", "yara");
|
|
87
|
+
}
|
|
88
|
+
// Development path: src/scanner/checks -> zoo/signatures/yara
|
|
89
|
+
const devPath = join(__dirname, "..", "..", "..", "zoo", "signatures", "yara");
|
|
90
|
+
try {
|
|
91
|
+
await access(devPath);
|
|
92
|
+
return devPath;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Not found, try installed path
|
|
96
|
+
}
|
|
97
|
+
// Installed path: dist/scanner/checks -> zoo/signatures/yara
|
|
98
|
+
const installedPath = join(__dirname, "..", "..", "zoo", "signatures", "yara");
|
|
99
|
+
try {
|
|
100
|
+
await access(installedPath);
|
|
101
|
+
return installedPath;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Fall back to dev path (will error with helpful message later)
|
|
105
|
+
return devPath;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Cached result of findYaraRulesDir
|
|
109
|
+
let cachedYaraRulesDir;
|
|
110
|
+
/**
|
|
111
|
+
* Get the default YARA rules directory (cached)
|
|
112
|
+
*/
|
|
113
|
+
export async function getDefaultYaraRulesDir() {
|
|
114
|
+
if (!cachedYaraRulesDir) {
|
|
115
|
+
cachedYaraRulesDir = await findYaraRulesDir();
|
|
116
|
+
}
|
|
117
|
+
return cachedYaraRulesDir;
|
|
118
|
+
}
|
|
119
|
+
// For backwards compatibility - returns a path that may not exist until findYaraRulesDir is called
|
|
120
|
+
export const DEFAULT_YARA_RULES_DIR = join(__dirname, "..", "..", "..", "zoo", "signatures", "yara");
|
|
121
|
+
/**
|
|
122
|
+
* Check if YARA-X is installed and available
|
|
123
|
+
*/
|
|
124
|
+
export async function isYaraAvailable() {
|
|
125
|
+
try {
|
|
126
|
+
const { stdout } = await execFileAsync("yr", ["--version"]);
|
|
127
|
+
return stdout.trim().length > 0;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get YARA-X version string
|
|
135
|
+
*/
|
|
136
|
+
export async function getYaraVersion() {
|
|
137
|
+
try {
|
|
138
|
+
const { stdout } = await execFileAsync("yr", ["--version"]);
|
|
139
|
+
return stdout.trim();
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* List all YARA rule files in a directory
|
|
147
|
+
*/
|
|
148
|
+
export async function listYaraRules(rulesDir) {
|
|
149
|
+
try {
|
|
150
|
+
const entries = await readdir(rulesDir);
|
|
151
|
+
return entries.filter((f) => f.endsWith(".yar") || f.endsWith(".yara"));
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse YARA output into structured matches
|
|
159
|
+
*/
|
|
160
|
+
function parseYaraOutput(output) {
|
|
161
|
+
const matches = [];
|
|
162
|
+
const lines = output.trim().split("\n").filter(Boolean);
|
|
163
|
+
for (const line of lines) {
|
|
164
|
+
// YARA output format: rule_name file_path
|
|
165
|
+
// With -s flag: rule_name file_path\n0xoffset:$string_name: string_content
|
|
166
|
+
const match = line.match(/^(\S+)\s+(.+)$/);
|
|
167
|
+
if (match) {
|
|
168
|
+
const [, rule, file] = match;
|
|
169
|
+
if (rule && file) {
|
|
170
|
+
matches.push({ rule, file });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return matches;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Cache for parsed YARA rule metadata to avoid re-reading files
|
|
178
|
+
*/
|
|
179
|
+
const ruleMetaCache = new Map();
|
|
180
|
+
/**
|
|
181
|
+
* Parse YARA rule file and extract metadata for all rules
|
|
182
|
+
*/
|
|
183
|
+
async function parseRuleFile(ruleFile) {
|
|
184
|
+
if (ruleMetaCache.has(ruleFile)) {
|
|
185
|
+
return ruleMetaCache.get(ruleFile);
|
|
186
|
+
}
|
|
187
|
+
const { readFile } = await import("node:fs/promises");
|
|
188
|
+
const ruleMap = new Map();
|
|
189
|
+
try {
|
|
190
|
+
const content = await readFile(ruleFile, "utf8");
|
|
191
|
+
// Match rule blocks: rule NAME { meta: ... }
|
|
192
|
+
const rulePattern = /rule\s+(\w+)\s*\{[^}]*meta\s*:\s*([^}]+?)(?:strings|condition)\s*:/gs;
|
|
193
|
+
for (const match of content.matchAll(rulePattern)) {
|
|
194
|
+
const ruleName = match[1];
|
|
195
|
+
const metaBlock = match[2];
|
|
196
|
+
if (!ruleName || !metaBlock)
|
|
197
|
+
continue;
|
|
198
|
+
const meta = {};
|
|
199
|
+
// Extract severity from meta block
|
|
200
|
+
const severityMatch = metaBlock.match(/severity\s*=\s*["'](\w+)["']/);
|
|
201
|
+
if (severityMatch?.[1]) {
|
|
202
|
+
meta.severity = severityMatch[1];
|
|
203
|
+
}
|
|
204
|
+
// Extract description from meta block
|
|
205
|
+
const descMatch = metaBlock.match(/description\s*=\s*["']([^"']+)["']/);
|
|
206
|
+
if (descMatch?.[1]) {
|
|
207
|
+
meta.description = descMatch[1];
|
|
208
|
+
}
|
|
209
|
+
ruleMap.set(ruleName, meta);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// If we can't read the file, return empty map
|
|
214
|
+
}
|
|
215
|
+
ruleMetaCache.set(ruleFile, ruleMap);
|
|
216
|
+
return ruleMap;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Extract metadata from YARA rule file for a specific rule
|
|
220
|
+
*/
|
|
221
|
+
async function getRuleMeta(ruleFile, ruleName) {
|
|
222
|
+
const ruleMap = await parseRuleFile(ruleFile);
|
|
223
|
+
const meta = ruleMap.get(ruleName);
|
|
224
|
+
if (meta?.severity) {
|
|
225
|
+
return meta;
|
|
226
|
+
}
|
|
227
|
+
// Fallback: derive severity from rule name patterns
|
|
228
|
+
const result = {};
|
|
229
|
+
if (meta?.description) {
|
|
230
|
+
result.description = meta.description;
|
|
231
|
+
}
|
|
232
|
+
const lowerName = ruleName.toLowerCase();
|
|
233
|
+
if (lowerName.includes("critical") || lowerName.startsWith("mal_")) {
|
|
234
|
+
result.severity = "critical";
|
|
235
|
+
}
|
|
236
|
+
else if (lowerName.includes("stealth") ||
|
|
237
|
+
lowerName.startsWith("stealer_") ||
|
|
238
|
+
lowerName.startsWith("rat_") ||
|
|
239
|
+
lowerName.startsWith("c2_")) {
|
|
240
|
+
result.severity = "high";
|
|
241
|
+
}
|
|
242
|
+
else if (lowerName.startsWith("susp_") || lowerName.startsWith("loader_")) {
|
|
243
|
+
result.severity = "medium";
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
result.severity = "medium"; // Default
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Run YARA rules against extension contents
|
|
252
|
+
*/
|
|
253
|
+
export async function checkYara(contents, rulesDir) {
|
|
254
|
+
const findings = [];
|
|
255
|
+
const targetRulesDir = rulesDir ?? (await getDefaultYaraRulesDir());
|
|
256
|
+
// Check if YARA is available
|
|
257
|
+
const available = await isYaraAvailable();
|
|
258
|
+
if (!available) {
|
|
259
|
+
findings.push({
|
|
260
|
+
id: "YARA_NOT_INSTALLED",
|
|
261
|
+
title: "YARA-X scanner not available",
|
|
262
|
+
description: "YARA-X is not installed. Install with 'brew install yara-x' to enable advanced malware detection using signature rules.",
|
|
263
|
+
severity: "low",
|
|
264
|
+
category: "yara",
|
|
265
|
+
metadata: {
|
|
266
|
+
suggestion: "brew install yara-x",
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
return findings;
|
|
270
|
+
}
|
|
271
|
+
// Check if rules directory exists and has rules
|
|
272
|
+
const rules = await listYaraRules(targetRulesDir);
|
|
273
|
+
if (rules.length === 0) {
|
|
274
|
+
return findings;
|
|
275
|
+
}
|
|
276
|
+
// Create a temporary directory for scanning
|
|
277
|
+
const tempDir = join(tmpdir(), `vsix-audit-${Date.now()}`);
|
|
278
|
+
try {
|
|
279
|
+
// Write extension files to temp directory for YARA to scan
|
|
280
|
+
const { mkdir } = await import("node:fs/promises");
|
|
281
|
+
await mkdir(tempDir, { recursive: true });
|
|
282
|
+
for (const [filename, buffer] of contents.files) {
|
|
283
|
+
// Skip binary files that are too large
|
|
284
|
+
if (buffer.length > 10 * 1024 * 1024)
|
|
285
|
+
continue; // Skip files > 10MB
|
|
286
|
+
// Skip binary files that cause false positives
|
|
287
|
+
if (shouldSkipForYara(filename))
|
|
288
|
+
continue;
|
|
289
|
+
const filePath = join(tempDir, filename);
|
|
290
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
291
|
+
await writeFile(filePath, buffer);
|
|
292
|
+
}
|
|
293
|
+
// Run YARA against the temp directory with all rules
|
|
294
|
+
for (const ruleFile of rules) {
|
|
295
|
+
const rulePath = join(targetRulesDir, ruleFile);
|
|
296
|
+
try {
|
|
297
|
+
// Run YARA-X with recursive scanning
|
|
298
|
+
// Using execFile instead of exec to prevent command injection
|
|
299
|
+
const { stdout, stderr } = await execFileAsync("yr", ["scan", "-r", rulePath, tempDir], { maxBuffer: 10 * 1024 * 1024 });
|
|
300
|
+
if (stderr && !stderr.includes("warning")) {
|
|
301
|
+
// YARA-X errors (not warnings) indicate rule issues
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const matches = parseYaraOutput(stdout);
|
|
305
|
+
for (const match of matches) {
|
|
306
|
+
// Get rule metadata
|
|
307
|
+
const meta = await getRuleMeta(rulePath, match.rule);
|
|
308
|
+
// Convert temp path back to relative path
|
|
309
|
+
const relativePath = match.file.replace(tempDir + "/", "");
|
|
310
|
+
// Get file extension for metadata
|
|
311
|
+
const fileExt = relativePath.slice(relativePath.lastIndexOf(".")).toLowerCase();
|
|
312
|
+
findings.push({
|
|
313
|
+
id: `YARA_${match.rule}`,
|
|
314
|
+
title: `YARA rule match: ${match.rule}`,
|
|
315
|
+
description: `YARA rule "${match.rule}" from ${ruleFile} matched this file. This indicates the file contains patterns associated with known malware or suspicious behavior.`,
|
|
316
|
+
severity: meta.severity ?? "medium",
|
|
317
|
+
category: "yara",
|
|
318
|
+
location: {
|
|
319
|
+
file: relativePath,
|
|
320
|
+
},
|
|
321
|
+
metadata: {
|
|
322
|
+
rule: match.rule,
|
|
323
|
+
ruleFile,
|
|
324
|
+
fileType: fileExt,
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
// YARA returns exit code 1 when no matches, which throws in exec
|
|
331
|
+
// Only log actual errors
|
|
332
|
+
if (error instanceof Error && !error.message.includes("exit code 1")) {
|
|
333
|
+
// Silently ignore scan errors for individual rules
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
// Clean up temp directory
|
|
340
|
+
try {
|
|
341
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Ignore cleanup errors
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return findings;
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=yara.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yara.js","sourceRoot":"","sources":["../../../src/scanner/checks/yara.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,WAAW;IACX,OAAO;IACP,MAAM;IACN,MAAM;IACN,SAAS;IACT,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;IACP,QAAQ;IACR,MAAM;IACN,cAAc;IACd,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,WAAW;IACX,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,YAAY;IACZ,MAAM;IACN,2DAA2D;IAC3D,OAAO;IACP,MAAM;IACN,QAAQ;IACR,KAAK;IACL,MAAM;IACN,eAAe;IACf,MAAM;IACN,MAAM;CACP,CAAC,CAAC;AAEH;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACpE,OAAO,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;;;;;GAMG;AACH,KAAK,UAAU,gBAAgB;IAC7B,mCAAmC;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,8DAA8D;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;IAED,6DAA6D;IAC7D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC5B,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,oCAAoC;AACpC,IAAI,kBAAsC,CAAC;AAE3C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,kBAAkB,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CACxC,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,MAAM,CACP,CAAC;AASF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,0CAA0C;QAC1C,2EAA2E;QAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC3C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;YAC7B,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoE,CAAC;AAElG;;GAEG;AACH,KAAK,UAAU,aAAa,CAC1B,QAAgB;IAEhB,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;IACtC,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuD,CAAC;IAE/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEjD,6CAA6C;QAC7C,MAAM,WAAW,GAAG,sEAAsE,CAAC;QAE3F,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAE3B,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;gBAAE,SAAS;YAEtC,MAAM,IAAI,GAAgD,EAAE,CAAC;YAE7D,mCAAmC;YACnC,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACtE,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACnC,CAAC;YAED,sCAAsC;YACtC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxE,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAClC,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8CAA8C;IAChD,CAAC;IAED,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,WAAW,CACxB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oDAAoD;IACpD,MAAM,MAAM,GAAgD,EAAE,CAAC;IAC/D,IAAI,IAAI,EAAE,WAAW,EAAE,CAAC;QACtB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACxC,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACzC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,CAAC,QAAQ,GAAG,UAAU,CAAC;IAC/B,CAAC;SAAM,IACL,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC7B,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC;QAChC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;QAC5B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAC3B,CAAC;QACD,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC;IAC3B,CAAC;SAAM,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5E,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,UAAU;IACxC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAsB,EAAE,QAAiB;IACvE,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,cAAc,GAAG,QAAQ,IAAI,CAAC,MAAM,sBAAsB,EAAE,CAAC,CAAC;IAEpE,6BAA6B;IAC7B,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;IAC1C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,oBAAoB;YACxB,KAAK,EAAE,8BAA8B;YACrC,WAAW,EACT,yHAAyH;YAC3H,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,MAAM;YAChB,QAAQ,EAAE;gBACR,UAAU,EAAE,qBAAqB;aAClC;SACF,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gDAAgD;IAChD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,4CAA4C;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAE3D,IAAI,CAAC;QACH,2DAA2D;QAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACnD,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAChD,uCAAuC;YACvC,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;gBAAE,SAAS,CAAC,oBAAoB;YAEpE,+CAA+C;YAC/C,IAAI,iBAAiB,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACzC,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAED,qDAAqD;QACrD,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;YAEhD,IAAI,CAAC;gBACH,qCAAqC;gBACrC,8DAA8D;gBAC9D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAC5C,IAAI,EACJ,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EACjC,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAChC,CAAC;gBAEF,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC1C,oDAAoD;oBACpD,SAAS;gBACX,CAAC;gBAED,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;gBAExC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,oBAAoB;oBACpB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBAErD,0CAA0C;oBAC1C,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;oBAE3D,kCAAkC;oBAClC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;oBAEhF,QAAQ,CAAC,IAAI,CAAC;wBACZ,EAAE,EAAE,QAAQ,KAAK,CAAC,IAAI,EAAE;wBACxB,KAAK,EAAE,oBAAoB,KAAK,CAAC,IAAI,EAAE;wBACvC,WAAW,EAAE,cAAc,KAAK,CAAC,IAAI,UAAU,QAAQ,qHAAqH;wBAC5K,QAAQ,EAAG,IAAI,CAAC,QAAmD,IAAI,QAAQ;wBAC/E,QAAQ,EAAE,MAAM;wBAChB,QAAQ,EAAE;4BACR,IAAI,EAAE,YAAY;yBACnB;wBACD,QAAQ,EAAE;4BACR,IAAI,EAAE,KAAK,CAAC,IAAI;4BAChB,QAAQ;4BACR,QAAQ,EAAE,OAAO;yBAClB;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,iEAAiE;gBACjE,yBAAyB;gBACzB,IAAI,KAAK,YAAY,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;oBACrE,mDAAmD;gBACrD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,0BAA0B;QAC1B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yara.test.d.ts","sourceRoot":"","sources":["../../../src/scanner/checks/yara.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { checkYara, getYaraVersion, isYaraAvailable, listYaraRules } from "./yara.js";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const ZOO_YARA_DIR = join(__dirname, "..", "..", "..", "zoo", "signatures", "yara");
|
|
7
|
+
function makeContents(files) {
|
|
8
|
+
const manifest = {
|
|
9
|
+
name: "test-extension",
|
|
10
|
+
publisher: "test",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
};
|
|
13
|
+
const fileMap = new Map();
|
|
14
|
+
for (const [name, content] of Object.entries(files)) {
|
|
15
|
+
fileMap.set(name, Buffer.from(content, "utf8"));
|
|
16
|
+
}
|
|
17
|
+
return { manifest, files: fileMap, basePath: "/test" };
|
|
18
|
+
}
|
|
19
|
+
describe("isYaraAvailable", () => {
|
|
20
|
+
it("returns boolean indicating YARA installation status", async () => {
|
|
21
|
+
const result = await isYaraAvailable();
|
|
22
|
+
// This will be true if yara is installed, false otherwise
|
|
23
|
+
expect(typeof result).toBe("boolean");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe("getYaraVersion", () => {
|
|
27
|
+
it("returns version string or null", async () => {
|
|
28
|
+
const result = await getYaraVersion();
|
|
29
|
+
if (result !== null) {
|
|
30
|
+
// If YARA is installed, version should be a non-empty string
|
|
31
|
+
expect(result.length).toBeGreaterThan(0);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe("listYaraRules", () => {
|
|
36
|
+
it("lists YARA rule files in zoo directory", async () => {
|
|
37
|
+
const rules = await listYaraRules(ZOO_YARA_DIR);
|
|
38
|
+
// We should have some YARA rules in the zoo
|
|
39
|
+
expect(Array.isArray(rules)).toBe(true);
|
|
40
|
+
// All files should have .yar or .yara extension
|
|
41
|
+
expect(rules.every((r) => r.endsWith(".yar") || r.endsWith(".yara"))).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
it("returns empty array for non-existent directory", async () => {
|
|
44
|
+
const rules = await listYaraRules("/nonexistent/path");
|
|
45
|
+
expect(rules).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("checkYara", () => {
|
|
49
|
+
it("returns appropriate result based on YARA availability", async () => {
|
|
50
|
+
const available = await isYaraAvailable();
|
|
51
|
+
const contents = makeContents({ "test.js": "console.log('test');" });
|
|
52
|
+
const findings = await checkYara(contents);
|
|
53
|
+
if (!available) {
|
|
54
|
+
// When YARA is not installed, should return informational finding
|
|
55
|
+
expect(findings).toHaveLength(1);
|
|
56
|
+
expect(findings.some((f) => f.id === "YARA_NOT_INSTALLED")).toBe(true);
|
|
57
|
+
expect(findings.some((f) => f.severity === "low")).toBe(true);
|
|
58
|
+
const finding = findings.find((f) => f.id === "YARA_NOT_INSTALLED");
|
|
59
|
+
expect(finding?.metadata?.["suggestion"]).toBe("brew install yara-x");
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// When YARA is installed, should return scan results (possibly empty)
|
|
63
|
+
expect(Array.isArray(findings)).toBe(true);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it("returns empty findings for clean extension when YARA is available", async () => {
|
|
67
|
+
const available = await isYaraAvailable();
|
|
68
|
+
if (!available)
|
|
69
|
+
return; // Skip if YARA not installed
|
|
70
|
+
const contents = makeContents({
|
|
71
|
+
"extension.js": "console.log('Hello, World!');",
|
|
72
|
+
"package.json": JSON.stringify({ name: "test", version: "1.0.0" }),
|
|
73
|
+
});
|
|
74
|
+
const findings = await checkYara(contents);
|
|
75
|
+
// Should not match any YARA rules for clean code
|
|
76
|
+
const yaraMatches = findings.filter((f) => f.id.startsWith("YARA_") && f.id !== "YARA_NOT_INSTALLED");
|
|
77
|
+
expect(yaraMatches).toHaveLength(0);
|
|
78
|
+
});
|
|
79
|
+
it("handles extension with potentially suspicious content", async () => {
|
|
80
|
+
const available = await isYaraAvailable();
|
|
81
|
+
if (!available)
|
|
82
|
+
return; // Skip if YARA not installed
|
|
83
|
+
// Create content that might match YARA rules
|
|
84
|
+
// This includes variation selectors (U+FE00-FE0F) and eval
|
|
85
|
+
const suspiciousContent = `
|
|
86
|
+
const payload = "test\uFE01\uFE02\uFE03";
|
|
87
|
+
eval(atob(payload));
|
|
88
|
+
`;
|
|
89
|
+
const contents = makeContents({
|
|
90
|
+
"extension.js": suspiciousContent,
|
|
91
|
+
});
|
|
92
|
+
const findings = await checkYara(contents);
|
|
93
|
+
// Should return array of findings (might match rules depending on rule content)
|
|
94
|
+
expect(Array.isArray(findings)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
it("includes metadata when rules match", async () => {
|
|
97
|
+
const available = await isYaraAvailable();
|
|
98
|
+
if (!available)
|
|
99
|
+
return; // Skip if YARA not installed
|
|
100
|
+
const contents = makeContents({
|
|
101
|
+
"extension.js": `
|
|
102
|
+
const wallet = "metamask";
|
|
103
|
+
const key = ".ssh/id_rsa";
|
|
104
|
+
eval(Buffer.from("Y29kZQ==", "base64").toString());
|
|
105
|
+
`,
|
|
106
|
+
});
|
|
107
|
+
const findings = await checkYara(contents);
|
|
108
|
+
// If any YARA rules matched, finding ID should include rule name
|
|
109
|
+
for (const finding of findings) {
|
|
110
|
+
if (finding.id !== "YARA_NOT_INSTALLED") {
|
|
111
|
+
expect(finding.id).toMatch(/^YARA_/);
|
|
112
|
+
expect(finding.metadata?.["rule"]).toBeDefined();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
it("handles empty extension gracefully", async () => {
|
|
117
|
+
const available = await isYaraAvailable();
|
|
118
|
+
if (!available)
|
|
119
|
+
return; // Skip if YARA not installed
|
|
120
|
+
const contents = makeContents({});
|
|
121
|
+
const findings = await checkYara(contents);
|
|
122
|
+
// Should not throw and should return array
|
|
123
|
+
expect(Array.isArray(findings)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=yara.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yara.test.js","sourceRoot":"","sources":["../../../src/scanner/checks/yara.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEtF,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;AAEpF,SAAS,YAAY,CAAC,KAA6B;IACjD,MAAM,QAAQ,GAAiB;QAC7B,IAAI,EAAE,gBAAgB;QACtB,SAAS,EAAE,MAAM;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACzD,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;QAEvC,0DAA0D;QAC1D,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;QAEtC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,6DAA6D;YAC7D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;QAEhD,4CAA4C;QAC5C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,gDAAgD;QAChD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,mBAAmB,CAAC,CAAC;QAEvD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC,CAAC;QACrE,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,kEAAkE;YAClE,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,oBAAoB,CAAC,CAAC;YACpE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACxE,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,6BAA6B;QAErD,MAAM,QAAQ,GAAG,YAAY,CAAC;YAC5B,cAAc,EAAE,+BAA+B;YAC/C,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;SACnE,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE3C,iDAAiD;QACjD,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,oBAAoB,CACjE,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,6BAA6B;QAErD,6CAA6C;QAC7C,2DAA2D;QAC3D,MAAM,iBAAiB,GAAG;;;KAGzB,CAAC;QAEF,MAAM,QAAQ,GAAG,YAAY,CAAC;YAC5B,cAAc,EAAE,iBAAiB;SAClC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE3C,gFAAgF;QAChF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,6BAA6B;QAErD,MAAM,QAAQ,GAAG,YAAY,CAAC;YAC5B,cAAc,EAAE;;;;OAIf;SACF,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE3C,iEAAiE;QACjE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,EAAE,KAAK,oBAAoB,EAAE,CAAC;gBACxC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,6BAA6B;QAErD,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;QAElC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE3C,2CAA2C;QAC3C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File extensions that can be scanned for code patterns.
|
|
3
|
+
* Used by pattern, IOC, and unicode checks.
|
|
4
|
+
*/
|
|
5
|
+
/** Code files - JavaScript, TypeScript, and script files */
|
|
6
|
+
export declare const CODE_EXTENSIONS: Set<string>;
|
|
7
|
+
/** Data files that may contain IOCs */
|
|
8
|
+
export declare const DATA_EXTENSIONS: Set<string>;
|
|
9
|
+
/** Text files for unicode analysis */
|
|
10
|
+
export declare const TEXT_EXTENSIONS: Set<string>;
|
|
11
|
+
/** All scannable extensions for IOC checks (code + data) */
|
|
12
|
+
export declare const SCANNABLE_EXTENSIONS_IOC: Set<string>;
|
|
13
|
+
/** Scannable extensions for pattern checks (code only) */
|
|
14
|
+
export declare const SCANNABLE_EXTENSIONS_PATTERN: Set<string>;
|
|
15
|
+
/** Scannable extensions for unicode checks (code + data + text) */
|
|
16
|
+
export declare const SCANNABLE_EXTENSIONS_UNICODE: Set<string>;
|
|
17
|
+
export declare function isScannable(filename: string, extensions: Set<string>): boolean;
|
|
18
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/scanner/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,4DAA4D;AAC5D,eAAO,MAAM,eAAe,aAY1B,CAAC;AAEH,uCAAuC;AACvC,eAAO,MAAM,eAAe,aAAqB,CAAC;AAElD,sCAAsC;AACtC,eAAO,MAAM,eAAe,aAA2B,CAAC;AAExD,4DAA4D;AAC5D,eAAO,MAAM,wBAAwB,aAAoD,CAAC;AAE1F,0DAA0D;AAC1D,eAAO,MAAM,4BAA4B,aAAkB,CAAC;AAE5D,mEAAmE;AACnE,eAAO,MAAM,4BAA4B,aAIvC,CAAC;AAEH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAG9E"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File extensions that can be scanned for code patterns.
|
|
3
|
+
* Used by pattern, IOC, and unicode checks.
|
|
4
|
+
*/
|
|
5
|
+
/** Code files - JavaScript, TypeScript, and script files */
|
|
6
|
+
export const CODE_EXTENSIONS = new Set([
|
|
7
|
+
".js",
|
|
8
|
+
".ts",
|
|
9
|
+
".mjs",
|
|
10
|
+
".cjs",
|
|
11
|
+
".jsx",
|
|
12
|
+
".tsx",
|
|
13
|
+
".ps1",
|
|
14
|
+
".sh",
|
|
15
|
+
".bat",
|
|
16
|
+
".cmd",
|
|
17
|
+
".py",
|
|
18
|
+
]);
|
|
19
|
+
/** Data files that may contain IOCs */
|
|
20
|
+
export const DATA_EXTENSIONS = new Set([".json"]);
|
|
21
|
+
/** Text files for unicode analysis */
|
|
22
|
+
export const TEXT_EXTENSIONS = new Set([".md", ".txt"]);
|
|
23
|
+
/** All scannable extensions for IOC checks (code + data) */
|
|
24
|
+
export const SCANNABLE_EXTENSIONS_IOC = new Set([...CODE_EXTENSIONS, ...DATA_EXTENSIONS]);
|
|
25
|
+
/** Scannable extensions for pattern checks (code only) */
|
|
26
|
+
export const SCANNABLE_EXTENSIONS_PATTERN = CODE_EXTENSIONS;
|
|
27
|
+
/** Scannable extensions for unicode checks (code + data + text) */
|
|
28
|
+
export const SCANNABLE_EXTENSIONS_UNICODE = new Set([
|
|
29
|
+
...CODE_EXTENSIONS,
|
|
30
|
+
...DATA_EXTENSIONS,
|
|
31
|
+
...TEXT_EXTENSIONS,
|
|
32
|
+
]);
|
|
33
|
+
export function isScannable(filename, extensions) {
|
|
34
|
+
const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase();
|
|
35
|
+
return extensions.has(ext);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/scanner/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;CACN,CAAC,CAAC;AAEH,uCAAuC;AACvC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAElD,sCAAsC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAExD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC;AAE1F,0DAA0D;AAC1D,MAAM,CAAC,MAAM,4BAA4B,GAAG,eAAe,CAAC;AAE5D,mEAAmE;AACnE,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,GAAG,CAAC;IAClD,GAAG,eAAe;IAClB,GAAG,eAAe;IAClB,GAAG,eAAe;CACnB,CAAC,CAAC;AAEH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,UAAuB;IACnE,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACpE,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection-coverage.test.d.ts","sourceRoot":"","sources":["../../src/scanner/detection-coverage.test.ts"],"names":[],"mappings":""}
|