tangkal 1.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/README.md +62 -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/src/analyzers/dependencies.d.ts +4 -0
- package/dist/src/analyzers/dependencies.d.ts.map +1 -0
- package/dist/src/analyzers/dependencies.js +79 -0
- package/dist/src/analyzers/dependencies.js.map +1 -0
- package/dist/src/analyzers/network.d.ts +17 -0
- package/dist/src/analyzers/network.d.ts.map +1 -0
- package/dist/src/analyzers/network.js +203 -0
- package/dist/src/analyzers/network.js.map +1 -0
- package/dist/src/analyzers/static-analysis.d.ts +18 -0
- package/dist/src/analyzers/static-analysis.d.ts.map +1 -0
- package/dist/src/analyzers/static-analysis.js +246 -0
- package/dist/src/analyzers/static-analysis.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +112 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +9 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +40 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/scanner.d.ts +8 -0
- package/dist/src/scanner.d.ts.map +1 -0
- package/dist/src/scanner.js +115 -0
- package/dist/src/scanner.js.map +1 -0
- package/dist/src/utils/entropy.d.ts +7 -0
- package/dist/src/utils/entropy.d.ts.map +1 -0
- package/dist/src/utils/entropy.js +25 -0
- package/dist/src/utils/entropy.js.map +1 -0
- package/dist/src/utils/ignore.d.ts +3 -0
- package/dist/src/utils/ignore.d.ts.map +1 -0
- package/dist/src/utils/ignore.js +18 -0
- package/dist/src/utils/ignore.js.map +1 -0
- package/dist/src/utils/lockfile.d.ts +9 -0
- package/dist/src/utils/lockfile.d.ts.map +1 -0
- package/dist/src/utils/lockfile.js +143 -0
- package/dist/src/utils/lockfile.js.map +1 -0
- package/dist/src/utils/popular-packages.d.ts +2 -0
- package/dist/src/utils/popular-packages.d.ts.map +1 -0
- package/dist/src/utils/popular-packages.js +22 -0
- package/dist/src/utils/popular-packages.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { parse } from '@babel/parser';
|
|
2
|
+
import _traverse from '@babel/traverse';
|
|
3
|
+
import { isObfuscated, hasLongLines } from '../utils/entropy.js';
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
const traverse = _traverse.default || _traverse;
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
export async function analyzeStream(filePath) {
|
|
9
|
+
const findings = [];
|
|
10
|
+
const fileStream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
11
|
+
const rl = readline.createInterface({
|
|
12
|
+
input: fileStream,
|
|
13
|
+
crlfDelay: Infinity
|
|
14
|
+
});
|
|
15
|
+
let lineIndex = 0;
|
|
16
|
+
let sampleContent = '';
|
|
17
|
+
const SAMPLE_SIZE = 5000;
|
|
18
|
+
for await (const line of rl) {
|
|
19
|
+
lineIndex++;
|
|
20
|
+
if (line.length > 1000) {
|
|
21
|
+
findings.push({
|
|
22
|
+
type: 'Heuristic',
|
|
23
|
+
name: 'Massive Line Length',
|
|
24
|
+
file: filePath,
|
|
25
|
+
line: lineIndex,
|
|
26
|
+
severity: 'high',
|
|
27
|
+
content: `Line length: ${line.length} chars`,
|
|
28
|
+
description: 'Extremely long line detected (Streaming Scan).'
|
|
29
|
+
});
|
|
30
|
+
rl.close();
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
if (sampleContent.length < SAMPLE_SIZE) {
|
|
34
|
+
sampleContent += line + '\n';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (sampleContent.length > 0 && isObfuscated(sampleContent)) {
|
|
38
|
+
findings.push({
|
|
39
|
+
type: 'Heuristic',
|
|
40
|
+
name: 'High Entropy',
|
|
41
|
+
file: filePath,
|
|
42
|
+
line: 0,
|
|
43
|
+
severity: 'medium',
|
|
44
|
+
content: 'File content appears random/encrypted',
|
|
45
|
+
description: 'Shannon entropy is abnormally high (Sampled).'
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return findings;
|
|
49
|
+
}
|
|
50
|
+
export function analyzeContent(content, file) {
|
|
51
|
+
const findings = [];
|
|
52
|
+
const lines = content.split('\n');
|
|
53
|
+
const isJson = file.endsWith('.json');
|
|
54
|
+
if (isJson)
|
|
55
|
+
return [];
|
|
56
|
+
if (content.length > 1024 * 1024) {
|
|
57
|
+
const longLine = hasLongLines(content);
|
|
58
|
+
if (longLine) {
|
|
59
|
+
findings.push({
|
|
60
|
+
type: 'Heuristic',
|
|
61
|
+
name: 'Massive Line Length',
|
|
62
|
+
file,
|
|
63
|
+
line: longLine.lineIndex,
|
|
64
|
+
severity: 'high',
|
|
65
|
+
content: `Line length: ${longLine.length} chars`,
|
|
66
|
+
description: 'Extremely long line detected (File too large for AST).'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
}
|
|
71
|
+
// AST Analysis
|
|
72
|
+
try {
|
|
73
|
+
const ast = parse(content, {
|
|
74
|
+
sourceType: 'unambiguous',
|
|
75
|
+
plugins: ['typescript', 'jsx']
|
|
76
|
+
});
|
|
77
|
+
traverse(ast, {
|
|
78
|
+
CallExpression(path) {
|
|
79
|
+
const callee = path.node.callee;
|
|
80
|
+
const line = path.node.loc?.start.line || 0;
|
|
81
|
+
const rawLine = lines[line - 1];
|
|
82
|
+
const codeSnippet = rawLine ? rawLine.trim() : 'N/A';
|
|
83
|
+
// eval()
|
|
84
|
+
if (callee.type === 'Identifier' && callee.name === 'eval') {
|
|
85
|
+
findings.push({
|
|
86
|
+
type: 'AST',
|
|
87
|
+
name: 'Dynamic Execution',
|
|
88
|
+
file,
|
|
89
|
+
line,
|
|
90
|
+
severity: 'high',
|
|
91
|
+
content: codeSnippet,
|
|
92
|
+
description: 'Use of eval() detected. Vulnerable to code injection.'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// child_process, fs, net, etc.
|
|
96
|
+
if (callee.type === 'MemberExpression') {
|
|
97
|
+
const obj = callee.object;
|
|
98
|
+
const prop = callee.property;
|
|
99
|
+
if (obj.type === 'Identifier' && prop.type === 'Identifier') {
|
|
100
|
+
if (obj.name === 'child_process') {
|
|
101
|
+
findings.push({
|
|
102
|
+
type: 'AST',
|
|
103
|
+
name: 'Shell Execution',
|
|
104
|
+
file,
|
|
105
|
+
line,
|
|
106
|
+
severity: 'medium',
|
|
107
|
+
content: codeSnippet,
|
|
108
|
+
description: `Executes system commands: ${obj.name}.${prop.name}(...)`
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (obj.name === 'fs' || obj.name === 'fs/promises') {
|
|
112
|
+
findings.push({
|
|
113
|
+
type: 'AST',
|
|
114
|
+
name: 'File System Access',
|
|
115
|
+
file,
|
|
116
|
+
line,
|
|
117
|
+
severity: 'medium',
|
|
118
|
+
content: codeSnippet,
|
|
119
|
+
description: `Accesses file system: ${obj.name}.${prop.name}(...)`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (['net', 'http', 'https', 'dgram', 'tls'].includes(obj.name)) {
|
|
123
|
+
findings.push({
|
|
124
|
+
type: 'AST',
|
|
125
|
+
name: 'Network Access',
|
|
126
|
+
file,
|
|
127
|
+
line,
|
|
128
|
+
severity: 'medium',
|
|
129
|
+
content: codeSnippet,
|
|
130
|
+
description: `Establishes network connection: ${obj.name}.${prop.name}(...)`
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// Buffer.from(..., 'base64')
|
|
134
|
+
if (obj.name === 'Buffer' && prop.name === 'from') {
|
|
135
|
+
const args = path.node.arguments;
|
|
136
|
+
if (args.length > 1 && args[1].type === 'StringLiteral' && args[1].value === 'base64') {
|
|
137
|
+
findings.push({
|
|
138
|
+
type: 'AST',
|
|
139
|
+
name: 'Base64 Decoding',
|
|
140
|
+
file,
|
|
141
|
+
line,
|
|
142
|
+
severity: 'medium',
|
|
143
|
+
content: codeSnippet,
|
|
144
|
+
description: 'Decodes Base64 content. Often used to hide payloads.'
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
MemberExpression(path) {
|
|
152
|
+
// process.env
|
|
153
|
+
const line = path.node.loc?.start.line || 0;
|
|
154
|
+
const rawLine = lines[line - 1];
|
|
155
|
+
const codeSnippet = rawLine ? rawLine.trim() : 'N/A';
|
|
156
|
+
if (path.node.object.type === 'Identifier' && path.node.object.name === 'process' &&
|
|
157
|
+
path.node.property.type === 'Identifier' && path.node.property.name === 'env') {
|
|
158
|
+
findings.push({
|
|
159
|
+
type: 'AST',
|
|
160
|
+
name: 'Environment Access',
|
|
161
|
+
file,
|
|
162
|
+
line,
|
|
163
|
+
severity: 'low',
|
|
164
|
+
content: codeSnippet,
|
|
165
|
+
description: 'Accesses environment variables (process.env).'
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
StringLiteral(path) {
|
|
170
|
+
const val = path.node.value;
|
|
171
|
+
const line = path.node.loc?.start.line || 0;
|
|
172
|
+
const rawLine = lines[line - 1];
|
|
173
|
+
const codeSnippet = rawLine ? rawLine.trim() : val;
|
|
174
|
+
if (/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/.test(val)) {
|
|
175
|
+
if (val !== '127.0.0.1' && val !== '0.0.0.0') {
|
|
176
|
+
findings.push({
|
|
177
|
+
type: 'AST',
|
|
178
|
+
name: 'Suspicious IP',
|
|
179
|
+
file,
|
|
180
|
+
line,
|
|
181
|
+
severity: 'medium',
|
|
182
|
+
content: codeSnippet,
|
|
183
|
+
description: `Contains hardcoded IP address: ${val}`
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (val.startsWith('http://') || (val.startsWith('https://') && !val.includes('npmjs') && !val.includes('github'))) {
|
|
188
|
+
findings.push({
|
|
189
|
+
type: 'AST',
|
|
190
|
+
name: 'Suspicious URL',
|
|
191
|
+
file,
|
|
192
|
+
line,
|
|
193
|
+
severity: 'medium',
|
|
194
|
+
content: codeSnippet,
|
|
195
|
+
description: `Contains hardcoded URL: ${val}`
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
NewExpression(path) {
|
|
200
|
+
const callee = path.node.callee;
|
|
201
|
+
const line = path.node.loc?.start.line || 0;
|
|
202
|
+
const rawLine = lines[line - 1];
|
|
203
|
+
const codeSnippet = rawLine ? rawLine.trim() : 'new Function(...)';
|
|
204
|
+
if (callee.type === 'Identifier' && callee.name === 'Function') {
|
|
205
|
+
findings.push({
|
|
206
|
+
type: 'AST',
|
|
207
|
+
name: 'Dynamic Execution',
|
|
208
|
+
file,
|
|
209
|
+
line,
|
|
210
|
+
severity: 'high',
|
|
211
|
+
content: codeSnippet,
|
|
212
|
+
description: 'Creates function from string (new Function). Vulnerable to injection.'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (e) { }
|
|
219
|
+
// 2. Heuristics (Long Lines)
|
|
220
|
+
const longLine = hasLongLines(content);
|
|
221
|
+
if (longLine) {
|
|
222
|
+
findings.push({
|
|
223
|
+
type: 'Heuristic',
|
|
224
|
+
name: 'Massive Line Length',
|
|
225
|
+
file,
|
|
226
|
+
line: longLine.lineIndex,
|
|
227
|
+
severity: 'high',
|
|
228
|
+
content: `Line length: ${longLine.length} chars`,
|
|
229
|
+
description: 'Extremely long line detected. Often indicates minified malware or packed code.'
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// 3. Entropy Check (Obfuscation)
|
|
233
|
+
if (!file.endsWith('.json') && isObfuscated(content)) {
|
|
234
|
+
findings.push({
|
|
235
|
+
type: 'Heuristic',
|
|
236
|
+
name: 'High Entropy',
|
|
237
|
+
file,
|
|
238
|
+
line: 0,
|
|
239
|
+
severity: 'medium',
|
|
240
|
+
content: 'File content appears random/encrypted',
|
|
241
|
+
description: 'Shannon entropy is abnormally high.'
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return findings;
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=static-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-analysis.js","sourceRoot":"","sources":["../../../src/analyzers/static-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AA4HA,wBAAsB,GAAG,kBAExB"}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import { scanDirectory } from './scanner.js';
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('tangkal')
|
|
10
|
+
.description('Preventive security scanner for cloned repositories')
|
|
11
|
+
.version('1.1.0')
|
|
12
|
+
.argument('[directory]', 'directory to scan', '.')
|
|
13
|
+
.option('--json', 'output results as JSON')
|
|
14
|
+
.option('--no-audit', 'skip npm audit check')
|
|
15
|
+
.option('--nuke', 'interactive mode to delete suspicious files')
|
|
16
|
+
.action(async (directory, options) => {
|
|
17
|
+
try {
|
|
18
|
+
const results = await scanDirectory(directory, options);
|
|
19
|
+
if (options.json) {
|
|
20
|
+
console.log(JSON.stringify(results, null, 2));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (results.length === 0) {
|
|
24
|
+
console.log(chalk.green.bold('\nOK: No suspicious patterns found.'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Separate vulnerabilities from other results for special formatting
|
|
28
|
+
const vulnerabilities = results.filter(f => f.type === 'Vulnerability');
|
|
29
|
+
const otherResults = results.filter(f => f.type !== 'Vulnerability');
|
|
30
|
+
if (otherResults.length > 0) {
|
|
31
|
+
console.log(chalk.red.bold('\n===================================='));
|
|
32
|
+
console.log(chalk.red.bold('ALERT: Malicious Code Detected'));
|
|
33
|
+
console.log(chalk.red.bold('===================================='));
|
|
34
|
+
otherResults.forEach(f => {
|
|
35
|
+
console.log(chalk.red('--------------------------------------------------'));
|
|
36
|
+
console.log(`${chalk.red.bold('TYPE:')} ${chalk.white.bold(f.name || f.type)} ${chalk.gray(`(Severity: ${f.severity.toUpperCase()})`)}`);
|
|
37
|
+
console.log(`${chalk.cyan('FILE:')} ${chalk.white(f.file)}:${chalk.yellow(f.line || 0)}`);
|
|
38
|
+
console.log(`${chalk.cyan('DESC:')} ${chalk.yellow(f.description)}`);
|
|
39
|
+
if (f.content) {
|
|
40
|
+
console.log(chalk.cyan('CODE:'));
|
|
41
|
+
console.log(chalk.bgBlack.white(` ${f.content.trim()} `));
|
|
42
|
+
}
|
|
43
|
+
console.log('');
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (vulnerabilities.length > 0) {
|
|
47
|
+
console.log(chalk.red.bold('\n===================================='));
|
|
48
|
+
console.log(chalk.red.bold('ALERT: Vulnerable Package'));
|
|
49
|
+
console.log(chalk.red.bold('===================================='));
|
|
50
|
+
// Sort by severity (Critical first)
|
|
51
|
+
const severityOrder = { 'critical': 0, 'high': 1, 'moderate': 2, 'medium': 2, 'low': 3 };
|
|
52
|
+
vulnerabilities.sort((a, b) => (severityOrder[a.severity] ?? 99) - (severityOrder[b.severity] ?? 99));
|
|
53
|
+
vulnerabilities.forEach(v => {
|
|
54
|
+
const fixedIn = v.fixedIn || 'latest';
|
|
55
|
+
const severityColor = (v.severity === 'critical' || v.severity === 'high') ? chalk.red.bold : chalk.yellow;
|
|
56
|
+
const pkgLabel = chalk.magenta(`${v.name}@${v.version}`);
|
|
57
|
+
console.log(chalk.green(`[SOLUTION]: Upgrade ${v.name}@${v.version} to ${v.name}@${fixedIn} to fix.`));
|
|
58
|
+
let links = `[${v.url}]`;
|
|
59
|
+
if (v.references && v.references.length) {
|
|
60
|
+
const snyk = v.references.find(r => r.includes('snyk.io'));
|
|
61
|
+
if (snyk)
|
|
62
|
+
links += ` [${snyk}]`;
|
|
63
|
+
}
|
|
64
|
+
console.log(`${chalk.white('[')}${severityColor(v.severity.toUpperCase())}${chalk.white(' Severity]')} ${chalk.blue(links)}`);
|
|
65
|
+
console.log(`${pkgLabel} ${chalk.white(v.summary)}`);
|
|
66
|
+
console.log(chalk.dim(`introduced by ${v.name}@${v.version}`));
|
|
67
|
+
console.log('');
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// Nuke Mode
|
|
71
|
+
if (options.nuke) {
|
|
72
|
+
const filesToDelete = [...new Set(results.map(r => r.file))];
|
|
73
|
+
const { selected } = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'checkbox',
|
|
76
|
+
name: 'selected',
|
|
77
|
+
message: 'Select files to DELETE (Space to select, Enter to confirm):',
|
|
78
|
+
choices: filesToDelete
|
|
79
|
+
}
|
|
80
|
+
]);
|
|
81
|
+
if (selected.length > 0) {
|
|
82
|
+
const { confirm } = await inquirer.prompt([{
|
|
83
|
+
type: 'confirm',
|
|
84
|
+
name: 'confirm',
|
|
85
|
+
message: `Are you sure you want to PERMANENTLY delete ${selected.length} files?`,
|
|
86
|
+
default: false
|
|
87
|
+
}]);
|
|
88
|
+
if (confirm) {
|
|
89
|
+
for (const file of selected) {
|
|
90
|
+
await fs.unlink(path.resolve(directory, file));
|
|
91
|
+
console.log(chalk.red(`Deleted: ${file}`));
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.green('Cleanup complete.'));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(chalk.red.bold('FAIL: Potential threats found.'));
|
|
99
|
+
console.log(chalk.yellow('Review manually or run with --nuke to delete files interactively.'));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error(chalk.red.bold('\nFATAL ERROR:'), error.message || error);
|
|
104
|
+
if (error.stack)
|
|
105
|
+
console.error(chalk.gray(error.stack));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
export async function run() {
|
|
110
|
+
await program.parseAsync();
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface Pattern {
|
|
2
|
+
name: string;
|
|
3
|
+
regex: RegExp;
|
|
4
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const PATTERNS: Pattern[];
|
|
8
|
+
export declare const POPULAR_PACKAGES: string[];
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,QAAQ,EAAE,OAAO,EA+B7B,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,MAAM,EAKpC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
name: 'Dynamic Execution',
|
|
4
|
+
regex: /\b(eval|new\s+Function)\b/g,
|
|
5
|
+
severity: 'high',
|
|
6
|
+
description: 'Executes arbitrary code strings.'
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'Base64 Decoding',
|
|
10
|
+
regex: /\b(atob|Buffer\.from\(.*['"]base64['"]\))/g,
|
|
11
|
+
severity: 'medium',
|
|
12
|
+
description: 'Often used to hide payloads.'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'Suspicious Network',
|
|
16
|
+
regex: /\b(axios|fetch|https?:\.get)\s*\(.*(atob|Buffer|token|api|model)\b/gi,
|
|
17
|
+
severity: 'high',
|
|
18
|
+
description: 'Network call with decoded/suspicious params.'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'Hex Obfuscation',
|
|
22
|
+
regex: /\\x[0-9a-fA-F]{2}/g,
|
|
23
|
+
severity: 'medium',
|
|
24
|
+
description: 'Hex-encoded strings used for obfuscation.'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Shell Execution',
|
|
28
|
+
regex: /\b(child_process|exec|spawn|fork)\b/g,
|
|
29
|
+
severity: 'medium',
|
|
30
|
+
description: 'Executes system commands.'
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
// A small list of very popular packages to check against for typosquatting
|
|
34
|
+
export const POPULAR_PACKAGES = [
|
|
35
|
+
'react', 'react-dom', 'next', 'vue', 'express', 'lodash', 'commander',
|
|
36
|
+
'chalk', 'axios', 'tslib', 'typescript', 'eslint', 'jest', 'moment',
|
|
37
|
+
'date-fns', 'uuid', 'classnames', 'prop-types', 'webpack', 'babel-core',
|
|
38
|
+
'body-parser', 'cookie-parser', 'dotenv', 'mongoose', 'nodemon'
|
|
39
|
+
];
|
|
40
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,QAAQ,GAAc;IACjC;QACE,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,4BAA4B;QACnC,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,kCAAkC;KAChD;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,4CAA4C;QACnD,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,8BAA8B;KAC5C;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,uEAAuE;QAC9E,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,8CAA8C;KAC5D;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,oBAAoB;QAC3B,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,2CAA2C;KACzD;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,sCAAsC;QAC7C,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,2BAA2B;KACzC;CACF,CAAC;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAa;IACxC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW;IACrE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ;IACnE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY;IACvE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS;CAChE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Finding } from './analyzers/static-analysis.js';
|
|
2
|
+
interface ScanOptions {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
skipAudit?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function scanDirectory(directory: string, options?: ScanOptions): Promise<Finding[]>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/scanner.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiC,KAAK,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAK7F,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAmHpG"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import { loadIgnore } from './utils/ignore.js';
|
|
7
|
+
import { analyzeContent, analyzeStream } from './analyzers/static-analysis.js';
|
|
8
|
+
import { checkTyposquatting } from './analyzers/dependencies.js';
|
|
9
|
+
import { auditDependencies } from './analyzers/network.js';
|
|
10
|
+
import { parsePackageLock } from './utils/lockfile.js';
|
|
11
|
+
export async function scanDirectory(directory, options = {}) {
|
|
12
|
+
const targetDir = path.resolve(directory);
|
|
13
|
+
const ig = await loadIgnore(targetDir);
|
|
14
|
+
const allFindings = [];
|
|
15
|
+
// 1. Find Files (Streaming)
|
|
16
|
+
const stream = fg.stream(['**/*.{js,ts,jsx,tsx,json}'], {
|
|
17
|
+
cwd: targetDir,
|
|
18
|
+
dot: true,
|
|
19
|
+
ignore: ['**/node_modules/**', '**/.git/**']
|
|
20
|
+
});
|
|
21
|
+
if (!options.json) {
|
|
22
|
+
console.log(chalk.gray(`Scanning files from ${targetDir} (Streaming)...`));
|
|
23
|
+
}
|
|
24
|
+
let packageJsonFound = false;
|
|
25
|
+
// 2. Scan Content
|
|
26
|
+
for await (const entry of stream) {
|
|
27
|
+
const file = entry;
|
|
28
|
+
if (ig.ignores(file))
|
|
29
|
+
continue;
|
|
30
|
+
const filePath = path.join(targetDir, file);
|
|
31
|
+
try {
|
|
32
|
+
const stat = await fs.stat(filePath);
|
|
33
|
+
// Optimize: Stream large files (>1MB)
|
|
34
|
+
if (stat.size > 1024 * 1024) {
|
|
35
|
+
const streamFindings = await analyzeStream(filePath);
|
|
36
|
+
streamFindings.forEach(f => { f.file = file; allFindings.push(f); });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
// Standard Read for small files
|
|
40
|
+
let content = await fs.readFile(filePath, 'utf-8');
|
|
41
|
+
content = content.replace(/^\uFEFF/, '');
|
|
42
|
+
// Check package.json specifically
|
|
43
|
+
if (file === 'package.json') {
|
|
44
|
+
packageJsonFound = true;
|
|
45
|
+
try {
|
|
46
|
+
const pkg = JSON.parse(content);
|
|
47
|
+
// A. Lifecycle Scripts
|
|
48
|
+
const scripts = pkg.scripts || {};
|
|
49
|
+
const dangerousScripts = ['preinstall', 'postinstall', 'install'];
|
|
50
|
+
for (const name of dangerousScripts) {
|
|
51
|
+
if (scripts[name]) {
|
|
52
|
+
allFindings.push({
|
|
53
|
+
type: 'Lifecycle Script',
|
|
54
|
+
name: name,
|
|
55
|
+
file,
|
|
56
|
+
line: 0,
|
|
57
|
+
severity: 'critical',
|
|
58
|
+
content: scripts[name],
|
|
59
|
+
description: 'Dangerous lifecycle script that runs automatically on install.'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// B. Typosquatting (Async & Network-aware)
|
|
64
|
+
const typoFindings = await checkTyposquatting(pkg);
|
|
65
|
+
typoFindings.forEach(f => {
|
|
66
|
+
allFindings.push({ ...f, file });
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
// Error parsing or checking typosquat
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Static Code Analysis (AST)
|
|
74
|
+
const contentFindings = analyzeContent(content, file);
|
|
75
|
+
allFindings.push(...contentFindings);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
// failed to read file
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// 3. Network Audit (Reputation & Vulnerability)
|
|
82
|
+
if (!options.skipAudit) {
|
|
83
|
+
const lockDeps = await parsePackageLock(targetDir);
|
|
84
|
+
if (lockDeps && lockDeps.length > 0) {
|
|
85
|
+
if (!options.json)
|
|
86
|
+
console.log(chalk.gray('Running deep dependency audit...'));
|
|
87
|
+
const spinner = !options.json ? ora(`Auditing ${lockDeps.length} dependencies...`).start() : null;
|
|
88
|
+
const netFindings = await auditDependencies(lockDeps);
|
|
89
|
+
allFindings.push(...netFindings);
|
|
90
|
+
if (spinner)
|
|
91
|
+
spinner.succeed(`Audit complete: scanned ${lockDeps.length} packages.`);
|
|
92
|
+
}
|
|
93
|
+
else if (packageJsonFound) {
|
|
94
|
+
try {
|
|
95
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
96
|
+
const pkgContent = await fs.readFile(pkgPath, 'utf-8');
|
|
97
|
+
const pkg = JSON.parse(pkgContent);
|
|
98
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
99
|
+
const directDeps = Object.keys(deps).map(k => ({ name: k, version: deps[k].replace(/[\^~]/g, '') }));
|
|
100
|
+
if (directDeps.length > 0) {
|
|
101
|
+
if (!options.json)
|
|
102
|
+
console.log(chalk.gray('No lockfile found. Auditing direct dependencies...'));
|
|
103
|
+
const spinner = !options.json ? ora(`Auditing ${directDeps.length} direct dependencies...`).start() : null;
|
|
104
|
+
const netFindings = await auditDependencies(directDeps);
|
|
105
|
+
allFindings.push(...netFindings);
|
|
106
|
+
if (spinner)
|
|
107
|
+
spinner.succeed(`Audit complete: scanned ${directDeps.length} packages.`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (e) { }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return allFindings;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function calculateEntropy(text: string): number;
|
|
2
|
+
export declare function isObfuscated(text: string, threshold?: number): boolean;
|
|
3
|
+
export declare function hasLongLines(text: string, threshold?: number): {
|
|
4
|
+
lineIndex: number;
|
|
5
|
+
length: number;
|
|
6
|
+
} | null;
|
|
7
|
+
//# sourceMappingURL=entropy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../../src/utils/entropy.ts"],"names":[],"mappings":"AAKA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,OAAO,CAInE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASzG"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import _entropy from 'shannon-entropy';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const entropy = _entropy.default || _entropy;
|
|
5
|
+
export function calculateEntropy(text) {
|
|
6
|
+
if (typeof entropy !== 'function')
|
|
7
|
+
return 0;
|
|
8
|
+
return entropy(text);
|
|
9
|
+
}
|
|
10
|
+
export function isObfuscated(text, threshold = 4.5) {
|
|
11
|
+
// Common english text is around 3.5 - 4.5
|
|
12
|
+
// Packed/encrypted code often exceeds 5.0
|
|
13
|
+
return calculateEntropy(text) > threshold;
|
|
14
|
+
}
|
|
15
|
+
export function hasLongLines(text, threshold = 1000) {
|
|
16
|
+
const lines = text.split('\n');
|
|
17
|
+
for (let i = 0; i < lines.length; i++) {
|
|
18
|
+
const line = lines[i];
|
|
19
|
+
if (line && line.length > threshold) {
|
|
20
|
+
return { lineIndex: i + 1, length: line.length };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=entropy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.js","sourceRoot":"","sources":["../../../src/utils/entropy.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,aAAa;AACb,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC;AAE7C,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAS,GAAG,GAAG;IACxD,0CAA0C;IAC1C,0CAA0C;IAC1C,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAS,GAAG,IAAI;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YACpC,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QACnD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ignore.d.ts","sourceRoot":"","sources":["../../../src/utils/ignore.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAe7D"}
|