@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,399 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { checkObfuscation } from "./obfuscation.js";
|
|
3
|
+
function makeContents(files) {
|
|
4
|
+
const manifest = {
|
|
5
|
+
name: "test-extension",
|
|
6
|
+
publisher: "test",
|
|
7
|
+
version: "1.0.0",
|
|
8
|
+
};
|
|
9
|
+
const fileMap = new Map();
|
|
10
|
+
for (const [name, content] of Object.entries(files)) {
|
|
11
|
+
fileMap.set(name, Buffer.from(content, "utf8"));
|
|
12
|
+
}
|
|
13
|
+
return { manifest, files: fileMap, basePath: "/test" };
|
|
14
|
+
}
|
|
15
|
+
describe("checkObfuscation", () => {
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// ENTROPY DETECTION
|
|
18
|
+
// ============================================================================
|
|
19
|
+
describe("entropy detection", () => {
|
|
20
|
+
it("detects high entropy regions", () => {
|
|
21
|
+
// Generate high-entropy string using full alphanumeric charset (62 chars)
|
|
22
|
+
// Each char used ~equally = entropy near log2(62) ≈ 5.95 bits/char
|
|
23
|
+
// Threshold is 5.5, so this will trigger detection
|
|
24
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
25
|
+
let highEntropy = "";
|
|
26
|
+
for (let i = 0; i < 300; i++) {
|
|
27
|
+
highEntropy += chars[i % chars.length];
|
|
28
|
+
}
|
|
29
|
+
const content = `const data = "${highEntropy}";`;
|
|
30
|
+
const contents = makeContents({ "extension.js": content });
|
|
31
|
+
const findings = checkObfuscation(contents);
|
|
32
|
+
expect(findings.some((f) => f.id === "OBFUSCATION_HIGH_ENTROPY")).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it("ignores normal code with low entropy", () => {
|
|
35
|
+
const content = `
|
|
36
|
+
function hello() {
|
|
37
|
+
console.log("Hello, World!");
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
const contents = makeContents({ "extension.js": content });
|
|
42
|
+
const findings = checkObfuscation(contents);
|
|
43
|
+
expect(findings.some((f) => f.id === "OBFUSCATION_HIGH_ENTROPY")).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// UNICODE HIDING DETECTION
|
|
48
|
+
// ============================================================================
|
|
49
|
+
describe("Unicode - zero-width characters", () => {
|
|
50
|
+
it("detects zero-width space characters (U+200B)", () => {
|
|
51
|
+
// 3+ occurrences needed
|
|
52
|
+
const content = "const x\u200B = 'a\u200Bb\u200Bc';";
|
|
53
|
+
const contents = makeContents({ "extension.js": content });
|
|
54
|
+
const findings = checkObfuscation(contents);
|
|
55
|
+
expect(findings).toHaveLength(1);
|
|
56
|
+
expect(findings.some((f) => f.id === "ZERO_WIDTH_CHARS")).toBe(true);
|
|
57
|
+
expect(findings.some((f) => f.severity === "high")).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
it("detects zero-width joiner (U+200D)", () => {
|
|
60
|
+
const content = "const x\u200D = 'a\u200Db\u200Dc';";
|
|
61
|
+
const contents = makeContents({ "extension.js": content });
|
|
62
|
+
const findings = checkObfuscation(contents);
|
|
63
|
+
expect(findings).toHaveLength(1);
|
|
64
|
+
expect(findings.some((f) => f.id === "ZERO_WIDTH_CHARS")).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
it("ignores files with only 1-2 zero-width chars", () => {
|
|
67
|
+
const content = "const x\u200B = 'a\u200Bb';";
|
|
68
|
+
const contents = makeContents({ "extension.js": content });
|
|
69
|
+
const findings = checkObfuscation(contents);
|
|
70
|
+
const zeroWidthFinding = findings.find((f) => f.id === "ZERO_WIDTH_CHARS");
|
|
71
|
+
expect(zeroWidthFinding).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("Unicode - variation selectors (GlassWorm technique)", () => {
|
|
75
|
+
it("detects variation selectors (U+FE00-FE0F) when >= 50 present", () => {
|
|
76
|
+
// Implementation requires 50+ variation selectors (GlassWorm uses hundreds)
|
|
77
|
+
// Normal emoji use has far fewer variation selectors
|
|
78
|
+
const variations = Array(55).fill("\uFE0F").join("x");
|
|
79
|
+
const content = `const payload = "${variations}";`;
|
|
80
|
+
const contents = makeContents({ "extension.js": content });
|
|
81
|
+
const findings = checkObfuscation(contents);
|
|
82
|
+
expect(findings).toHaveLength(1);
|
|
83
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(true);
|
|
84
|
+
expect(findings.some((f) => f.severity === "critical")).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it("ignores few variation selectors (normal for emoji)", () => {
|
|
87
|
+
// Less than 50 variation selectors should be ignored (normal emoji use)
|
|
88
|
+
const content = "a\uFE00b\uFE01c\uFE02d\uFE0F";
|
|
89
|
+
const contents = makeContents({ "extension.js": content });
|
|
90
|
+
const findings = checkObfuscation(contents);
|
|
91
|
+
expect(findings.find((f) => f.id === "VARIATION_SELECTOR")).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe("Unicode - bidirectional overrides (Trojan Source)", () => {
|
|
95
|
+
it("detects left-to-right override (U+202D)", () => {
|
|
96
|
+
const content = "const admin\u202D = true;";
|
|
97
|
+
const contents = makeContents({ "extension.js": content });
|
|
98
|
+
const findings = checkObfuscation(contents);
|
|
99
|
+
expect(findings).toHaveLength(1);
|
|
100
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(true);
|
|
101
|
+
expect(findings.some((f) => f.severity === "critical")).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
it("detects right-to-left override (U+202E)", () => {
|
|
104
|
+
const content = "const admin\u202E = true;";
|
|
105
|
+
const contents = makeContents({ "extension.js": content });
|
|
106
|
+
const findings = checkObfuscation(contents);
|
|
107
|
+
expect(findings).toHaveLength(1);
|
|
108
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe("Unicode - ASCII escapes", () => {
|
|
112
|
+
it("detects excessive Unicode escapes for ASCII", () => {
|
|
113
|
+
// Using \\u00XX for normal printable ASCII is suspicious
|
|
114
|
+
const content = "const x = '\\u0068\\u0065\\u006c\\u006c\\u006f\\u0077';"; // "hellow"
|
|
115
|
+
const contents = makeContents({ "extension.js": content });
|
|
116
|
+
const findings = checkObfuscation(contents);
|
|
117
|
+
expect(findings).toHaveLength(1);
|
|
118
|
+
expect(findings.some((f) => f.id === "UNICODE_ASCII_ESCAPE")).toBe(true);
|
|
119
|
+
expect(findings.some((f) => f.severity === "medium")).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
it("ignores files with few Unicode escapes", () => {
|
|
122
|
+
const content = "const x = '\\u0068\\u0065';"; // Only 2 escapes
|
|
123
|
+
const contents = makeContents({ "extension.js": content });
|
|
124
|
+
const findings = checkObfuscation(contents);
|
|
125
|
+
const escapeFinding = findings.find((f) => f.id === "UNICODE_ASCII_ESCAPE");
|
|
126
|
+
expect(escapeFinding).toBeUndefined();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe("Unicode - Cyrillic homoglyphs", () => {
|
|
130
|
+
it("detects Cyrillic 'а' (U+0430) that looks like Latin 'a'", () => {
|
|
131
|
+
const content = "const \u0430dmin = true;"; // Cyrillic а
|
|
132
|
+
const contents = makeContents({ "extension.js": content });
|
|
133
|
+
const findings = checkObfuscation(contents);
|
|
134
|
+
expect(findings).toHaveLength(1);
|
|
135
|
+
expect(findings.some((f) => f.id === "CYRILLIC_HOMOGLYPH")).toBe(true);
|
|
136
|
+
expect(findings.some((f) => f.severity === "high")).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
it("detects Cyrillic 'е' (U+0435) that looks like Latin 'e'", () => {
|
|
139
|
+
const content = "const s\u0435cret = 'password';"; // Cyrillic е
|
|
140
|
+
const contents = makeContents({ "extension.js": content });
|
|
141
|
+
const findings = checkObfuscation(contents);
|
|
142
|
+
expect(findings).toHaveLength(1);
|
|
143
|
+
expect(findings.some((f) => f.id === "CYRILLIC_HOMOGLYPH")).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it("ignores Cyrillic in markdown files", () => {
|
|
146
|
+
const content = "# Hello \u0430nd welcome"; // Cyrillic а in markdown
|
|
147
|
+
const contents = makeContents({ "README.md": content });
|
|
148
|
+
const findings = checkObfuscation(contents);
|
|
149
|
+
const cyrillicFinding = findings.find((f) => f.id === "CYRILLIC_HOMOGLYPH");
|
|
150
|
+
expect(cyrillicFinding).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe("Unicode - invisible characters near code execution", () => {
|
|
154
|
+
it("flags many invisible chars in file with eval()", () => {
|
|
155
|
+
// Implementation requires 5+ invisible chars near execution patterns
|
|
156
|
+
const content = "const payload\uFE01\uFE02\uFE03\uFE04\uFE05 = 'data';\neval(payload);";
|
|
157
|
+
const contents = makeContents({ "extension.js": content });
|
|
158
|
+
const findings = checkObfuscation(contents);
|
|
159
|
+
expect(findings.some((f) => f.id === "INVISIBLE_CODE_EXECUTION")).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
it("flags many invisible chars in file with Function()", () => {
|
|
162
|
+
const content = "const x\uFE01\uFE02\uFE03\uFE04\uFE05 = 1;\nnew Function('return x')();";
|
|
163
|
+
const contents = makeContents({ "extension.js": content });
|
|
164
|
+
const findings = checkObfuscation(contents);
|
|
165
|
+
expect(findings.some((f) => f.id === "INVISIBLE_CODE_EXECUTION")).toBe(true);
|
|
166
|
+
});
|
|
167
|
+
it("flags many invisible chars in file with child_process", () => {
|
|
168
|
+
const content = "require('child_process').exec('ls');\nconst hidden\uFE01\uFE02\uFE03\uFE04\uFE05 = 1;";
|
|
169
|
+
const contents = makeContents({ "extension.js": content });
|
|
170
|
+
const findings = checkObfuscation(contents);
|
|
171
|
+
expect(findings.some((f) => f.id === "INVISIBLE_CODE_EXECUTION")).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
it("does NOT flag few invisible chars even with execution context", () => {
|
|
174
|
+
// Single invisible char isn't enough - needs 5+
|
|
175
|
+
const content = "const x\uFE01 = 1;\neval(x);";
|
|
176
|
+
const contents = makeContents({ "extension.js": content });
|
|
177
|
+
const findings = checkObfuscation(contents);
|
|
178
|
+
expect(findings.some((f) => f.id === "INVISIBLE_CODE_EXECUTION")).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe("file filtering", () => {
|
|
182
|
+
it("scans JavaScript files", () => {
|
|
183
|
+
// Use bidi override which triggers with just 1 occurrence
|
|
184
|
+
const content = "const admin\u202E = true;";
|
|
185
|
+
const contents = makeContents({ "test.js": content });
|
|
186
|
+
const findings = checkObfuscation(contents);
|
|
187
|
+
expect(findings.length).toBeGreaterThan(0);
|
|
188
|
+
});
|
|
189
|
+
it("scans TypeScript files", () => {
|
|
190
|
+
const content = "const admin\u202E: boolean = true;";
|
|
191
|
+
const contents = makeContents({ "test.ts": content });
|
|
192
|
+
const findings = checkObfuscation(contents);
|
|
193
|
+
expect(findings.length).toBeGreaterThan(0);
|
|
194
|
+
});
|
|
195
|
+
it("scans JSON files for unicode issues", () => {
|
|
196
|
+
const content = '{"key\u202E": "value"}';
|
|
197
|
+
const contents = makeContents({ "test.json": content });
|
|
198
|
+
const findings = checkObfuscation(contents);
|
|
199
|
+
expect(findings.length).toBeGreaterThan(0);
|
|
200
|
+
});
|
|
201
|
+
it("ignores binary files", () => {
|
|
202
|
+
// Even critical patterns should be ignored in binary files
|
|
203
|
+
const content = "\u202E\u202D\u202C";
|
|
204
|
+
const contents = makeContents({ "test.png": content });
|
|
205
|
+
const findings = checkObfuscation(contents);
|
|
206
|
+
expect(findings).toHaveLength(0);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
describe("metadata", () => {
|
|
210
|
+
it("includes match count in metadata for unicode findings", () => {
|
|
211
|
+
// Use BIDI_OVERRIDE which triggers with 1+ occurrences
|
|
212
|
+
const content = "a\u202Db\u202Ec\u202D";
|
|
213
|
+
const contents = makeContents({ "test.js": content });
|
|
214
|
+
const findings = checkObfuscation(contents);
|
|
215
|
+
const finding = findings.find((f) => f.id === "BIDI_OVERRIDE");
|
|
216
|
+
expect(finding?.metadata?.["matchCount"]).toBe(3);
|
|
217
|
+
});
|
|
218
|
+
it("includes code points in metadata for unicode findings", () => {
|
|
219
|
+
const content = "const admin\u202E = true;";
|
|
220
|
+
const contents = makeContents({ "test.js": content });
|
|
221
|
+
const findings = checkObfuscation(contents);
|
|
222
|
+
const finding = findings.find((f) => f.id === "BIDI_OVERRIDE");
|
|
223
|
+
const codePoints = finding?.metadata?.["codePoints"];
|
|
224
|
+
expect(codePoints).toBeDefined();
|
|
225
|
+
expect(codePoints?.some((cp) => cp.includes("202E"))).toBe(true);
|
|
226
|
+
});
|
|
227
|
+
it("includes line number in location", () => {
|
|
228
|
+
const content = "line1\nline2\nconst admin\u202E = true;";
|
|
229
|
+
const contents = makeContents({ "test.js": content });
|
|
230
|
+
const findings = checkObfuscation(contents);
|
|
231
|
+
const finding = findings.find((f) => f.id === "BIDI_OVERRIDE");
|
|
232
|
+
expect(finding?.location?.line).toBe(3);
|
|
233
|
+
});
|
|
234
|
+
it("includes obfuscation score for entropy findings", () => {
|
|
235
|
+
// Use full alphanumeric charset for high entropy (log2(62) ≈ 5.95 bits/char)
|
|
236
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
237
|
+
let highEntropy = "";
|
|
238
|
+
for (let i = 0; i < 300; i++) {
|
|
239
|
+
highEntropy += chars[i % chars.length];
|
|
240
|
+
}
|
|
241
|
+
const content = `const data = "${highEntropy}";`;
|
|
242
|
+
const contents = makeContents({ "test.js": content });
|
|
243
|
+
const findings = checkObfuscation(contents);
|
|
244
|
+
const finding = findings.find((f) => f.id === "OBFUSCATION_HIGH_ENTROPY");
|
|
245
|
+
expect(finding?.metadata?.["obfuscationScore"]).toBeGreaterThan(0);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
// ============================================================================
|
|
249
|
+
// FALSE POSITIVE EXCLUSIONS
|
|
250
|
+
// ============================================================================
|
|
251
|
+
describe("false positive exclusions", () => {
|
|
252
|
+
describe("node_modules exclusions", () => {
|
|
253
|
+
it("skips high entropy detection in node_modules", () => {
|
|
254
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
255
|
+
let highEntropy = "";
|
|
256
|
+
for (let i = 0; i < 300; i++) {
|
|
257
|
+
highEntropy += chars[i % chars.length];
|
|
258
|
+
}
|
|
259
|
+
const content = `const data = "${highEntropy}";`;
|
|
260
|
+
const contents = makeContents({
|
|
261
|
+
"node_modules/iconv-lite/encodings/tables/cp437.js": content,
|
|
262
|
+
});
|
|
263
|
+
const findings = checkObfuscation(contents);
|
|
264
|
+
expect(findings.some((f) => f.id === "OBFUSCATION_HIGH_ENTROPY")).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
it("skips zero-width chars in node_modules", () => {
|
|
267
|
+
const content = "const x\u200B = 'a\u200Bb\u200Bc';"; // 3 zero-width spaces
|
|
268
|
+
const contents = makeContents({ "node_modules/moment/locale/ku.js": content });
|
|
269
|
+
const findings = checkObfuscation(contents);
|
|
270
|
+
expect(findings.some((f) => f.id === "ZERO_WIDTH_CHARS")).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
it("skips Cyrillic homoglyphs in node_modules", () => {
|
|
273
|
+
const content = "const \u0430dmin = true;"; // Cyrillic а
|
|
274
|
+
const contents = makeContents({ "node_modules/iconv-lite/lib/extend-node.js": content });
|
|
275
|
+
const findings = checkObfuscation(contents);
|
|
276
|
+
expect(findings.some((f) => f.id === "CYRILLIC_HOMOGLYPH")).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
it("still detects BIDI_OVERRIDE in node_modules (critical)", () => {
|
|
279
|
+
const content = "const admin\u202E = true;";
|
|
280
|
+
const contents = makeContents({ "node_modules/suspicious-package/index.js": content });
|
|
281
|
+
const findings = checkObfuscation(contents);
|
|
282
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(true);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
describe("emoji and entity file exclusions", () => {
|
|
286
|
+
it("skips variation selectors in emoji.json", () => {
|
|
287
|
+
// 50+ variation selectors would normally trigger
|
|
288
|
+
const variations = "\uFE0F".repeat(60);
|
|
289
|
+
const content = `{"emoji": "👍${variations}"}`;
|
|
290
|
+
const contents = makeContents({ "extension/out/emoji.json": content });
|
|
291
|
+
const findings = checkObfuscation(contents);
|
|
292
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(false);
|
|
293
|
+
});
|
|
294
|
+
it("skips variation selectors in entities.json", () => {
|
|
295
|
+
const variations = "\uFE0F".repeat(60);
|
|
296
|
+
const content = `{"entity": "test${variations}"}`;
|
|
297
|
+
const contents = makeContents({ "extension/out/entities.json": content });
|
|
298
|
+
const findings = checkObfuscation(contents);
|
|
299
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(false);
|
|
300
|
+
});
|
|
301
|
+
it("skips variation selectors in README.md", () => {
|
|
302
|
+
const variations = "\uFE0F".repeat(60);
|
|
303
|
+
const content = `# README\nEmoji test: ${variations}`;
|
|
304
|
+
const contents = makeContents({ "extension/README.md": content });
|
|
305
|
+
const findings = checkObfuscation(contents);
|
|
306
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(false);
|
|
307
|
+
});
|
|
308
|
+
it("still detects variation selectors in suspicious JS files", () => {
|
|
309
|
+
// 50+ variation selectors in a non-emoji file
|
|
310
|
+
const variations = Array(55).fill("\uFE00").join("x");
|
|
311
|
+
const content = `const payload = "${variations}"; eval(payload);`;
|
|
312
|
+
const contents = makeContents({ "extension.js": content });
|
|
313
|
+
const findings = checkObfuscation(contents);
|
|
314
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(true);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
describe("RTL file exclusions", () => {
|
|
318
|
+
it("skips BIDI_OVERRIDE in katex files", () => {
|
|
319
|
+
const content = "const rtl\u202E = true;";
|
|
320
|
+
const contents = makeContents({ "node_modules/katex/dist/katex.js": content });
|
|
321
|
+
const findings = checkObfuscation(contents);
|
|
322
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(false);
|
|
323
|
+
});
|
|
324
|
+
it("skips BIDI_OVERRIDE in mermaid files", () => {
|
|
325
|
+
const content = "const rtl\u202E = true;";
|
|
326
|
+
const contents = makeContents({ "node_modules/mermaid/dist/mermaid.js": content });
|
|
327
|
+
const findings = checkObfuscation(contents);
|
|
328
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(false);
|
|
329
|
+
});
|
|
330
|
+
it("skips BIDI_OVERRIDE in Hebrew language files", () => {
|
|
331
|
+
const content = "Hebrew text\u202Ehere";
|
|
332
|
+
const contents = makeContents({ "extension/resources/dia_he.txt": content });
|
|
333
|
+
const findings = checkObfuscation(contents);
|
|
334
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(false);
|
|
335
|
+
});
|
|
336
|
+
it("still detects BIDI_OVERRIDE in regular JS files", () => {
|
|
337
|
+
const content = "const admin\u202E = true;";
|
|
338
|
+
const contents = makeContents({ "extension/src/index.js": content });
|
|
339
|
+
const findings = checkObfuscation(contents);
|
|
340
|
+
expect(findings.some((f) => f.id === "BIDI_OVERRIDE")).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
describe("i18n file exclusions", () => {
|
|
344
|
+
it("skips Cyrillic in moment locale files", () => {
|
|
345
|
+
const content = "const \u0430dmin = '\u0435xample';"; // Cyrillic а and е
|
|
346
|
+
const contents = makeContents({ "moment/locale/ru.js": content });
|
|
347
|
+
const findings = checkObfuscation(contents);
|
|
348
|
+
expect(findings.some((f) => f.id === "CYRILLIC_HOMOGLYPH")).toBe(false);
|
|
349
|
+
});
|
|
350
|
+
it("skips Cyrillic in encoding table files", () => {
|
|
351
|
+
const content = "module.exports = { '\u0430': 0x00 };"; // Cyrillic а
|
|
352
|
+
const contents = makeContents({ "encodings/tables/cp866.js": content });
|
|
353
|
+
const findings = checkObfuscation(contents);
|
|
354
|
+
expect(findings.some((f) => f.id === "CYRILLIC_HOMOGLYPH")).toBe(false);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
describe("variation selector threshold", () => {
|
|
358
|
+
it("ignores fewer than 50 variation selectors (normal emoji use)", () => {
|
|
359
|
+
// 30 variation selectors - below threshold
|
|
360
|
+
const variations = Array(30).fill("\uFE0F").join("x");
|
|
361
|
+
const content = `const emoji = "${variations}";`;
|
|
362
|
+
const contents = makeContents({ "extension.js": content });
|
|
363
|
+
const findings = checkObfuscation(contents);
|
|
364
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(false);
|
|
365
|
+
});
|
|
366
|
+
it("detects 50+ variation selectors (GlassWorm technique)", () => {
|
|
367
|
+
// 55 variation selectors - above threshold
|
|
368
|
+
const variations = Array(55).fill("\uFE0F").join("x");
|
|
369
|
+
const content = `const payload = "${variations}";`;
|
|
370
|
+
const contents = makeContents({ "extension.js": content });
|
|
371
|
+
const findings = checkObfuscation(contents);
|
|
372
|
+
expect(findings.some((f) => f.id === "VARIATION_SELECTOR")).toBe(true);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
describe("category assignment", () => {
|
|
377
|
+
it("assigns obfuscation category to entropy findings", () => {
|
|
378
|
+
// Use full alphanumeric charset for high entropy (log2(62) ≈ 5.95 bits/char)
|
|
379
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
380
|
+
let highEntropy = "";
|
|
381
|
+
for (let i = 0; i < 300; i++) {
|
|
382
|
+
highEntropy += chars[i % chars.length];
|
|
383
|
+
}
|
|
384
|
+
const content = `const data = "${highEntropy}";`;
|
|
385
|
+
const contents = makeContents({ "test.js": content });
|
|
386
|
+
const findings = checkObfuscation(contents);
|
|
387
|
+
const finding = findings.find((f) => f.id === "OBFUSCATION_HIGH_ENTROPY");
|
|
388
|
+
expect(finding?.category).toBe("obfuscation");
|
|
389
|
+
});
|
|
390
|
+
it("assigns obfuscation category to unicode findings", () => {
|
|
391
|
+
const content = "const admin\u202E = true;";
|
|
392
|
+
const contents = makeContents({ "test.js": content });
|
|
393
|
+
const findings = checkObfuscation(contents);
|
|
394
|
+
const finding = findings.find((f) => f.id === "BIDI_OVERRIDE");
|
|
395
|
+
expect(finding?.category).toBe("obfuscation");
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
//# sourceMappingURL=obfuscation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obfuscation.test.js","sourceRoot":"","sources":["../../../src/scanner/checks/obfuscation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BlocklistEntry, Finding, VsixContents, VsixManifest, ZooData } from "../types.js";
|
|
2
|
+
interface PackageJson {
|
|
3
|
+
name?: string;
|
|
4
|
+
dependencies?: Record<string, string>;
|
|
5
|
+
devDependencies?: Record<string, string>;
|
|
6
|
+
scripts?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export declare function checkBlocklist(manifest: VsixManifest, blocklist: BlocklistEntry[]): Finding[];
|
|
9
|
+
export declare function checkActivationEvents(manifest: VsixManifest): Finding[];
|
|
10
|
+
export declare function checkThemeAbuse(manifest: VsixManifest): Finding[];
|
|
11
|
+
export declare function checkSuspiciousPermissions(manifest: VsixManifest): Finding[];
|
|
12
|
+
export declare function checkMaliciousPackages(packageJson: PackageJson, maliciousPackages: Set<string>): Finding[];
|
|
13
|
+
export declare function checkTyposquattingPackages(packageJson: PackageJson): Finding[];
|
|
14
|
+
export declare function checkLifecycleScripts(packageJson: PackageJson): Finding[];
|
|
15
|
+
export declare function checkPackage(contents: VsixContents, zooData: ZooData): Finding[];
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=package.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../../src/scanner/checks/package.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEhG,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAmLD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,EAAE,CAyB7F;AAID,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,CAmDvE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,CAsCjE;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,CAkC5E;AAID,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC7B,OAAO,EAAE,CAyBX;AAED,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,EAAE,CA6B9E;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,EAAE,CAuDzE;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CA4BhF"}
|