mitnick-cli 1.0.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 +21 -0
- package/README.md +193 -0
- package/dist/analyzers/analyzer.interface.d.ts +32 -0
- package/dist/analyzers/analyzer.interface.d.ts.map +1 -0
- package/dist/analyzers/analyzer.interface.js +2 -0
- package/dist/analyzers/analyzer.interface.js.map +1 -0
- package/dist/analyzers/analyzer.registry.d.ts +16 -0
- package/dist/analyzers/analyzer.registry.d.ts.map +1 -0
- package/dist/analyzers/analyzer.registry.js +40 -0
- package/dist/analyzers/analyzer.registry.js.map +1 -0
- package/dist/analyzers/dependency-confusion/index.d.ts +14 -0
- package/dist/analyzers/dependency-confusion/index.d.ts.map +1 -0
- package/dist/analyzers/dependency-confusion/index.js +147 -0
- package/dist/analyzers/dependency-confusion/index.js.map +1 -0
- package/dist/analyzers/dormant-package/index.d.ts +14 -0
- package/dist/analyzers/dormant-package/index.d.ts.map +1 -0
- package/dist/analyzers/dormant-package/index.js +137 -0
- package/dist/analyzers/dormant-package/index.js.map +1 -0
- package/dist/analyzers/file-based-analyzer.d.ts +20 -0
- package/dist/analyzers/file-based-analyzer.d.ts.map +1 -0
- package/dist/analyzers/file-based-analyzer.js +35 -0
- package/dist/analyzers/file-based-analyzer.js.map +1 -0
- package/dist/analyzers/install-scripts/index.d.ts +13 -0
- package/dist/analyzers/install-scripts/index.d.ts.map +1 -0
- package/dist/analyzers/install-scripts/index.js +125 -0
- package/dist/analyzers/install-scripts/index.js.map +1 -0
- package/dist/analyzers/license/index.d.ts +12 -0
- package/dist/analyzers/license/index.d.ts.map +1 -0
- package/dist/analyzers/license/index.js +199 -0
- package/dist/analyzers/license/index.js.map +1 -0
- package/dist/analyzers/maintainer/index.d.ts +12 -0
- package/dist/analyzers/maintainer/index.d.ts.map +1 -0
- package/dist/analyzers/maintainer/index.js +93 -0
- package/dist/analyzers/maintainer/index.js.map +1 -0
- package/dist/analyzers/network-calls/index.d.ts +15 -0
- package/dist/analyzers/network-calls/index.d.ts.map +1 -0
- package/dist/analyzers/network-calls/index.js +212 -0
- package/dist/analyzers/network-calls/index.js.map +1 -0
- package/dist/analyzers/obfuscation/index.d.ts +19 -0
- package/dist/analyzers/obfuscation/index.d.ts.map +1 -0
- package/dist/analyzers/obfuscation/index.js +218 -0
- package/dist/analyzers/obfuscation/index.js.map +1 -0
- package/dist/analyzers/prototype-pollution/index.d.ts +18 -0
- package/dist/analyzers/prototype-pollution/index.d.ts.map +1 -0
- package/dist/analyzers/prototype-pollution/index.js +257 -0
- package/dist/analyzers/prototype-pollution/index.js.map +1 -0
- package/dist/analyzers/sensitive-data/index.d.ts +16 -0
- package/dist/analyzers/sensitive-data/index.d.ts.map +1 -0
- package/dist/analyzers/sensitive-data/index.js +254 -0
- package/dist/analyzers/sensitive-data/index.js.map +1 -0
- package/dist/analyzers/typosquatting/index.d.ts +14 -0
- package/dist/analyzers/typosquatting/index.d.ts.map +1 -0
- package/dist/analyzers/typosquatting/index.js +127 -0
- package/dist/analyzers/typosquatting/index.js.map +1 -0
- package/dist/analyzers/typosquatting/popular-packages.d.ts +9 -0
- package/dist/analyzers/typosquatting/popular-packages.d.ts.map +1 -0
- package/dist/analyzers/typosquatting/popular-packages.js +236 -0
- package/dist/analyzers/typosquatting/popular-packages.js.map +1 -0
- package/dist/analyzers/vulnerability/index.d.ts +12 -0
- package/dist/analyzers/vulnerability/index.d.ts.map +1 -0
- package/dist/analyzers/vulnerability/index.js +147 -0
- package/dist/analyzers/vulnerability/index.js.map +1 -0
- package/dist/cli/commands/check.d.ts +21 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +204 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/formatters/formatter.interface.d.ts +14 -0
- package/dist/cli/formatters/formatter.interface.d.ts.map +1 -0
- package/dist/cli/formatters/formatter.interface.js +2 -0
- package/dist/cli/formatters/formatter.interface.js.map +1 -0
- package/dist/cli/formatters/json.d.ts +12 -0
- package/dist/cli/formatters/json.d.ts.map +1 -0
- package/dist/cli/formatters/json.js +12 -0
- package/dist/cli/formatters/json.js.map +1 -0
- package/dist/cli/formatters/sarif.d.ts +13 -0
- package/dist/cli/formatters/sarif.d.ts.map +1 -0
- package/dist/cli/formatters/sarif.js +101 -0
- package/dist/cli/formatters/sarif.js.map +1 -0
- package/dist/cli/formatters/terminal.d.ts +13 -0
- package/dist/cli/formatters/terminal.d.ts.map +1 -0
- package/dist/cli/formatters/terminal.js +110 -0
- package/dist/cli/formatters/terminal.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +86 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/engine.d.ts +23 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +55 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/scorer.d.ts +30 -0
- package/dist/core/scorer.d.ts.map +1 -0
- package/dist/core/scorer.js +88 -0
- package/dist/core/scorer.js.map +1 -0
- package/dist/core/types.d.ts +76 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +30 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/client.d.ts +27 -0
- package/dist/registry/client.d.ts.map +1 -0
- package/dist/registry/client.js +189 -0
- package/dist/registry/client.js.map +1 -0
- package/dist/registry/tarball.d.ts +34 -0
- package/dist/registry/tarball.d.ts.map +1 -0
- package/dist/registry/tarball.js +103 -0
- package/dist/registry/tarball.js.map +1 -0
- package/dist/utils/ast.d.ts +74 -0
- package/dist/utils/ast.d.ts.map +1 -0
- package/dist/utils/ast.js +150 -0
- package/dist/utils/ast.js.map +1 -0
- package/dist/utils/fs.d.ts +28 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +78 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/http.d.ts +40 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +116 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/logger.d.ts +46 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +91 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/strings.d.ts +8 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +12 -0
- package/dist/utils/strings.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typosquatting Analyzer — detects package names that are suspiciously
|
|
3
|
+
* similar to popular npm packages via Levenshtein distance and common
|
|
4
|
+
* character substitutions.
|
|
5
|
+
*/
|
|
6
|
+
import { POPULAR_PACKAGES } from './popular-packages.js';
|
|
7
|
+
import { logger } from '../../utils/logger.js';
|
|
8
|
+
/** Common character substitutions used in typosquatting. */
|
|
9
|
+
const SUBSTITUTIONS = [
|
|
10
|
+
{ from: '0', to: 'o' },
|
|
11
|
+
{ from: 'o', to: '0' },
|
|
12
|
+
{ from: '1', to: 'l' },
|
|
13
|
+
{ from: 'l', to: '1' },
|
|
14
|
+
{ from: 'rn', to: 'm' },
|
|
15
|
+
{ from: 'm', to: 'rn' },
|
|
16
|
+
{ from: '-', to: '_' },
|
|
17
|
+
{ from: '_', to: '-' },
|
|
18
|
+
];
|
|
19
|
+
// ─── Levenshtein ──────────────────────────────────────────
|
|
20
|
+
function levenshteinDistance(a, b) {
|
|
21
|
+
const la = a.length;
|
|
22
|
+
const lb = b.length;
|
|
23
|
+
if (la === 0)
|
|
24
|
+
return lb;
|
|
25
|
+
if (lb === 0)
|
|
26
|
+
return la;
|
|
27
|
+
// Use two-row approach for memory efficiency
|
|
28
|
+
let previousRow = Array.from({ length: lb + 1 }, (_, i) => i);
|
|
29
|
+
let currentRow = new Array(lb + 1);
|
|
30
|
+
for (let i = 1; i <= la; i++) {
|
|
31
|
+
currentRow[0] = i;
|
|
32
|
+
for (let j = 1; j <= lb; j++) {
|
|
33
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
34
|
+
const deletion = (previousRow[j] ?? 0) + 1;
|
|
35
|
+
const insertion = (currentRow[j - 1] ?? 0) + 1;
|
|
36
|
+
const substitution = (previousRow[j - 1] ?? 0) + cost;
|
|
37
|
+
currentRow[j] = Math.min(deletion, insertion, substitution);
|
|
38
|
+
}
|
|
39
|
+
[previousRow, currentRow] = [currentRow, previousRow];
|
|
40
|
+
}
|
|
41
|
+
return previousRow[lb] ?? la;
|
|
42
|
+
}
|
|
43
|
+
// ─── Substitution check ──────────────────────────────────
|
|
44
|
+
function applySubstitutions(name) {
|
|
45
|
+
const variants = [];
|
|
46
|
+
for (const { from, to } of SUBSTITUTIONS) {
|
|
47
|
+
let idx = name.indexOf(from);
|
|
48
|
+
while (idx !== -1) {
|
|
49
|
+
const variant = name.slice(0, idx) + to + name.slice(idx + from.length);
|
|
50
|
+
variants.push(variant);
|
|
51
|
+
idx = name.indexOf(from, idx + 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return variants;
|
|
55
|
+
}
|
|
56
|
+
// ─── Analyzer ─────────────────────────────────────────────
|
|
57
|
+
export class TyposquattingAnalyzer {
|
|
58
|
+
name = 'typosquatting';
|
|
59
|
+
description = 'Detects package names that may be typosquatting popular npm packages';
|
|
60
|
+
analyze(context) {
|
|
61
|
+
const start = performance.now();
|
|
62
|
+
const findings = [];
|
|
63
|
+
try {
|
|
64
|
+
const packageName = context.packageName;
|
|
65
|
+
// Skip scoped packages — they can't easily typosquat unscoped ones
|
|
66
|
+
// and skip if the name exactly matches a popular package
|
|
67
|
+
const normalizedName = packageName.replace(/^@[^/]+\//, '');
|
|
68
|
+
if (POPULAR_PACKAGES.includes(normalizedName)) {
|
|
69
|
+
return Promise.resolve({
|
|
70
|
+
analyzer: this.name,
|
|
71
|
+
findings: [],
|
|
72
|
+
duration: performance.now() - start,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Check Levenshtein distance against all popular packages
|
|
76
|
+
const alreadyFlagged = new Set();
|
|
77
|
+
for (const popular of POPULAR_PACKAGES) {
|
|
78
|
+
// Skip packages with very different lengths (distance would be too high)
|
|
79
|
+
if (Math.abs(normalizedName.length - popular.length) > 2)
|
|
80
|
+
continue;
|
|
81
|
+
const distance = levenshteinDistance(normalizedName, popular);
|
|
82
|
+
if (distance === 1) {
|
|
83
|
+
findings.push(this.createFinding(normalizedName, popular, 'high', distance));
|
|
84
|
+
alreadyFlagged.add(popular);
|
|
85
|
+
}
|
|
86
|
+
else if (distance === 2) {
|
|
87
|
+
findings.push(this.createFinding(normalizedName, popular, 'medium', distance));
|
|
88
|
+
alreadyFlagged.add(popular);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Check common character substitutions
|
|
92
|
+
const variants = applySubstitutions(normalizedName);
|
|
93
|
+
for (const variant of variants) {
|
|
94
|
+
if (POPULAR_PACKAGES.includes(variant) && !alreadyFlagged.has(variant)) {
|
|
95
|
+
findings.push({
|
|
96
|
+
analyzer: this.name,
|
|
97
|
+
severity: 'high',
|
|
98
|
+
title: `Possible typosquat of "${variant}"`,
|
|
99
|
+
description: `Package name "${normalizedName}" uses a common character substitution ` +
|
|
100
|
+
`that makes it look like the popular package "${variant}".`,
|
|
101
|
+
recommendation: `Verify you intended to install "${normalizedName}" and not "${variant}".`,
|
|
102
|
+
});
|
|
103
|
+
alreadyFlagged.add(variant);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
logger.warn(`[${this.name}] Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
109
|
+
}
|
|
110
|
+
return Promise.resolve({
|
|
111
|
+
analyzer: this.name,
|
|
112
|
+
findings,
|
|
113
|
+
duration: performance.now() - start,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
createFinding(name, popular, severity, distance) {
|
|
117
|
+
return {
|
|
118
|
+
analyzer: this.name,
|
|
119
|
+
severity,
|
|
120
|
+
title: `Possible typosquat of "${popular}" (distance: ${distance})`,
|
|
121
|
+
description: `Package name "${name}" has a Levenshtein distance of ${distance} from ` +
|
|
122
|
+
`the popular package "${popular}" (potential typosquatting).`,
|
|
123
|
+
recommendation: `Verify you intended to install "${name}" and not "${popular}".`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzers/typosquatting/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top 200 most popular npm package names.
|
|
3
|
+
*
|
|
4
|
+
* Used by the TyposquattingAnalyzer to detect package names that are
|
|
5
|
+
* suspiciously similar to well-known packages. This list is curated from
|
|
6
|
+
* npm download statistics and ecosystem prominence.
|
|
7
|
+
*/
|
|
8
|
+
export declare const POPULAR_PACKAGES: readonly string[];
|
|
9
|
+
//# sourceMappingURL=popular-packages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popular-packages.d.ts","sourceRoot":"","sources":["../../../src/analyzers/typosquatting/popular-packages.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAsPpC,CAAC"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top 200 most popular npm package names.
|
|
3
|
+
*
|
|
4
|
+
* Used by the TyposquattingAnalyzer to detect package names that are
|
|
5
|
+
* suspiciously similar to well-known packages. This list is curated from
|
|
6
|
+
* npm download statistics and ecosystem prominence.
|
|
7
|
+
*/
|
|
8
|
+
export const POPULAR_PACKAGES = [
|
|
9
|
+
// Frameworks & runtimes
|
|
10
|
+
'express',
|
|
11
|
+
'next',
|
|
12
|
+
'nuxt',
|
|
13
|
+
'react',
|
|
14
|
+
'react-dom',
|
|
15
|
+
'react-router',
|
|
16
|
+
'react-router-dom',
|
|
17
|
+
'vue',
|
|
18
|
+
'angular',
|
|
19
|
+
'svelte',
|
|
20
|
+
'preact',
|
|
21
|
+
'fastify',
|
|
22
|
+
'koa',
|
|
23
|
+
'hapi',
|
|
24
|
+
'nest',
|
|
25
|
+
'gatsby',
|
|
26
|
+
'remix',
|
|
27
|
+
// Bundlers & build tools
|
|
28
|
+
'webpack',
|
|
29
|
+
'vite',
|
|
30
|
+
'rollup',
|
|
31
|
+
'esbuild',
|
|
32
|
+
'parcel',
|
|
33
|
+
'turbo',
|
|
34
|
+
'tsup',
|
|
35
|
+
'swc',
|
|
36
|
+
// Transpilers & compilers
|
|
37
|
+
'typescript',
|
|
38
|
+
'babel-core',
|
|
39
|
+
'@babel/core',
|
|
40
|
+
'@babel/preset-env',
|
|
41
|
+
'coffeescript',
|
|
42
|
+
// Utilities
|
|
43
|
+
'lodash',
|
|
44
|
+
'underscore',
|
|
45
|
+
'ramda',
|
|
46
|
+
'rxjs',
|
|
47
|
+
'immer',
|
|
48
|
+
'date-fns',
|
|
49
|
+
'moment',
|
|
50
|
+
'dayjs',
|
|
51
|
+
'uuid',
|
|
52
|
+
'nanoid',
|
|
53
|
+
'ms',
|
|
54
|
+
// HTTP & networking
|
|
55
|
+
'axios',
|
|
56
|
+
'got',
|
|
57
|
+
'node-fetch',
|
|
58
|
+
'request',
|
|
59
|
+
'superagent',
|
|
60
|
+
'undici',
|
|
61
|
+
'ky',
|
|
62
|
+
// CLI
|
|
63
|
+
'commander',
|
|
64
|
+
'yargs',
|
|
65
|
+
'minimist',
|
|
66
|
+
'meow',
|
|
67
|
+
'inquirer',
|
|
68
|
+
'prompts',
|
|
69
|
+
'chalk',
|
|
70
|
+
'ora',
|
|
71
|
+
'cli-table3',
|
|
72
|
+
'figlet',
|
|
73
|
+
'boxen',
|
|
74
|
+
'listr2',
|
|
75
|
+
// Testing
|
|
76
|
+
'jest',
|
|
77
|
+
'mocha',
|
|
78
|
+
'chai',
|
|
79
|
+
'sinon',
|
|
80
|
+
'vitest',
|
|
81
|
+
'ava',
|
|
82
|
+
'tap',
|
|
83
|
+
'nyc',
|
|
84
|
+
'istanbul',
|
|
85
|
+
'cypress',
|
|
86
|
+
'playwright',
|
|
87
|
+
'puppeteer',
|
|
88
|
+
// Linting & formatting
|
|
89
|
+
'eslint',
|
|
90
|
+
'prettier',
|
|
91
|
+
'stylelint',
|
|
92
|
+
'standard',
|
|
93
|
+
'husky',
|
|
94
|
+
'lint-staged',
|
|
95
|
+
// Logging
|
|
96
|
+
'debug',
|
|
97
|
+
'winston',
|
|
98
|
+
'pino',
|
|
99
|
+
'bunyan',
|
|
100
|
+
'morgan',
|
|
101
|
+
'loglevel',
|
|
102
|
+
// Validation & schemas
|
|
103
|
+
'zod',
|
|
104
|
+
'joi',
|
|
105
|
+
'yup',
|
|
106
|
+
'ajv',
|
|
107
|
+
'validator',
|
|
108
|
+
'class-validator',
|
|
109
|
+
// Database & ORMs
|
|
110
|
+
'mongoose',
|
|
111
|
+
'sequelize',
|
|
112
|
+
'typeorm',
|
|
113
|
+
'prisma',
|
|
114
|
+
'knex',
|
|
115
|
+
'pg',
|
|
116
|
+
'mysql2',
|
|
117
|
+
'redis',
|
|
118
|
+
'ioredis',
|
|
119
|
+
'mongodb',
|
|
120
|
+
'sqlite3',
|
|
121
|
+
'better-sqlite3',
|
|
122
|
+
// Auth & security
|
|
123
|
+
'jsonwebtoken',
|
|
124
|
+
'bcrypt',
|
|
125
|
+
'bcryptjs',
|
|
126
|
+
'passport',
|
|
127
|
+
'helmet',
|
|
128
|
+
'cors',
|
|
129
|
+
'csurf',
|
|
130
|
+
'express-rate-limit',
|
|
131
|
+
// File & streams
|
|
132
|
+
'fs-extra',
|
|
133
|
+
'glob',
|
|
134
|
+
'globby',
|
|
135
|
+
'chokidar',
|
|
136
|
+
'rimraf',
|
|
137
|
+
'mkdirp',
|
|
138
|
+
'tar',
|
|
139
|
+
'archiver',
|
|
140
|
+
'unzipper',
|
|
141
|
+
'sharp',
|
|
142
|
+
'multer',
|
|
143
|
+
// Parsing
|
|
144
|
+
'cheerio',
|
|
145
|
+
'jsdom',
|
|
146
|
+
'marked',
|
|
147
|
+
'markdown-it',
|
|
148
|
+
'yaml',
|
|
149
|
+
'csv-parser',
|
|
150
|
+
'xml2js',
|
|
151
|
+
'fast-xml-parser',
|
|
152
|
+
'json5',
|
|
153
|
+
'toml',
|
|
154
|
+
// Process & system
|
|
155
|
+
'dotenv',
|
|
156
|
+
'cross-env',
|
|
157
|
+
'execa',
|
|
158
|
+
'shelljs',
|
|
159
|
+
'concurrently',
|
|
160
|
+
'nodemon',
|
|
161
|
+
'pm2',
|
|
162
|
+
'forever',
|
|
163
|
+
// Templating
|
|
164
|
+
'handlebars',
|
|
165
|
+
'ejs',
|
|
166
|
+
'pug',
|
|
167
|
+
'nunjucks',
|
|
168
|
+
'mustache',
|
|
169
|
+
// WebSocket & real-time
|
|
170
|
+
'socket.io',
|
|
171
|
+
'ws',
|
|
172
|
+
// Crypto
|
|
173
|
+
'crypto-js',
|
|
174
|
+
'tweetnacl',
|
|
175
|
+
'node-forge',
|
|
176
|
+
// Configuration
|
|
177
|
+
'config',
|
|
178
|
+
'convict',
|
|
179
|
+
'cosmiconfig',
|
|
180
|
+
'rc',
|
|
181
|
+
// Misc popular
|
|
182
|
+
'semver',
|
|
183
|
+
'minimatch',
|
|
184
|
+
'micromatch',
|
|
185
|
+
'picomatch',
|
|
186
|
+
'ansi-styles',
|
|
187
|
+
'ansi-regex',
|
|
188
|
+
'strip-ansi',
|
|
189
|
+
'supports-color',
|
|
190
|
+
'color-convert',
|
|
191
|
+
'wrap-ansi',
|
|
192
|
+
'string-width',
|
|
193
|
+
'cliui',
|
|
194
|
+
'escalade',
|
|
195
|
+
'escape-string-regexp',
|
|
196
|
+
'has-flag',
|
|
197
|
+
'p-limit',
|
|
198
|
+
'p-queue',
|
|
199
|
+
'yocto-queue',
|
|
200
|
+
'lru-cache',
|
|
201
|
+
'which',
|
|
202
|
+
'path-to-regexp',
|
|
203
|
+
'qs',
|
|
204
|
+
'query-string',
|
|
205
|
+
'form-data',
|
|
206
|
+
'mime',
|
|
207
|
+
'mime-types',
|
|
208
|
+
'content-type',
|
|
209
|
+
'accepts',
|
|
210
|
+
'negotiator',
|
|
211
|
+
'bytes',
|
|
212
|
+
'body-parser',
|
|
213
|
+
'cookie',
|
|
214
|
+
'cookie-parser',
|
|
215
|
+
'express-session',
|
|
216
|
+
'compression',
|
|
217
|
+
'serve-static',
|
|
218
|
+
'http-proxy',
|
|
219
|
+
'http-proxy-middleware',
|
|
220
|
+
'https-proxy-agent',
|
|
221
|
+
'proxy-agent',
|
|
222
|
+
'agent-base',
|
|
223
|
+
'depd',
|
|
224
|
+
'on-finished',
|
|
225
|
+
'raw-body',
|
|
226
|
+
'type-is',
|
|
227
|
+
'tslib',
|
|
228
|
+
'source-map',
|
|
229
|
+
'source-map-support',
|
|
230
|
+
'regenerator-runtime',
|
|
231
|
+
'core-js',
|
|
232
|
+
'async',
|
|
233
|
+
'bluebird',
|
|
234
|
+
'eventemitter3',
|
|
235
|
+
];
|
|
236
|
+
//# sourceMappingURL=popular-packages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popular-packages.js","sourceRoot":"","sources":["../../../src/analyzers/typosquatting/popular-packages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vulnerability Analyzer — queries the OSV API for known CVEs affecting
|
|
3
|
+
* the target package version.
|
|
4
|
+
*/
|
|
5
|
+
import type { Analyzer } from '../analyzer.interface.js';
|
|
6
|
+
import type { AnalysisContext, AnalyzerResult } from '../../core/types.js';
|
|
7
|
+
export declare class VulnerabilityAnalyzer implements Analyzer {
|
|
8
|
+
readonly name = "vulnerability-scanner";
|
|
9
|
+
readonly description = "Checks for known CVEs and security advisories via the OSV database";
|
|
10
|
+
analyze(context: AnalysisContext): Promise<AnalyzerResult>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyzers/vulnerability/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAqB,MAAM,qBAAqB,CAAC;AAoI9F,qBAAa,qBAAsB,YAAW,QAAQ;IACpD,QAAQ,CAAC,IAAI,2BAA2B;IACxC,QAAQ,CAAC,WAAW,wEAAwE;IAEtF,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CA0DjE"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vulnerability Analyzer — queries the OSV API for known CVEs affecting
|
|
3
|
+
* the target package version.
|
|
4
|
+
*/
|
|
5
|
+
import { fetchJson } from '../../utils/http.js';
|
|
6
|
+
import { logger } from '../../utils/logger.js';
|
|
7
|
+
// ─── Helpers ──────────────────────────────────────────────
|
|
8
|
+
const OSV_API_URL = 'https://api.osv.dev/v1/query';
|
|
9
|
+
function extractCveId(vuln) {
|
|
10
|
+
if (vuln.id.startsWith('CVE-'))
|
|
11
|
+
return vuln.id;
|
|
12
|
+
const alias = vuln.aliases?.find((a) => a.startsWith('CVE-'));
|
|
13
|
+
return alias ?? vuln.id;
|
|
14
|
+
}
|
|
15
|
+
function mapOsvSeverity(vuln) {
|
|
16
|
+
const severityEntries = vuln.severity;
|
|
17
|
+
if (!severityEntries || severityEntries.length === 0)
|
|
18
|
+
return 'medium';
|
|
19
|
+
// Look for CVSS v3 score first
|
|
20
|
+
for (const entry of severityEntries) {
|
|
21
|
+
if (entry.type === 'CVSS_V3') {
|
|
22
|
+
const score = parseCvssScore(entry.score);
|
|
23
|
+
if (score !== null) {
|
|
24
|
+
if (score >= 9.0)
|
|
25
|
+
return 'critical';
|
|
26
|
+
if (score >= 7.0)
|
|
27
|
+
return 'high';
|
|
28
|
+
if (score >= 4.0)
|
|
29
|
+
return 'medium';
|
|
30
|
+
return 'low';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Check database_specific for npm severity strings
|
|
35
|
+
const dbSeverity = vuln.database_specific?.['severity'];
|
|
36
|
+
if (typeof dbSeverity === 'string') {
|
|
37
|
+
const lower = dbSeverity.toLowerCase();
|
|
38
|
+
if (lower === 'critical')
|
|
39
|
+
return 'critical';
|
|
40
|
+
if (lower === 'high')
|
|
41
|
+
return 'high';
|
|
42
|
+
if (lower === 'moderate' || lower === 'medium')
|
|
43
|
+
return 'medium';
|
|
44
|
+
if (lower === 'low')
|
|
45
|
+
return 'low';
|
|
46
|
+
}
|
|
47
|
+
return 'medium';
|
|
48
|
+
}
|
|
49
|
+
function parseCvssScore(vector) {
|
|
50
|
+
// CVSS vector strings can start with "CVSS:3.x/" and may end with
|
|
51
|
+
// a score, or we need to parse from the vector itself.
|
|
52
|
+
// Some OSV entries put the numeric score directly.
|
|
53
|
+
const numeric = parseFloat(vector);
|
|
54
|
+
if (!isNaN(numeric) && numeric >= 0 && numeric <= 10)
|
|
55
|
+
return numeric;
|
|
56
|
+
// Try to extract base score from a CVSS vector by looking for a pattern
|
|
57
|
+
// Since full CVSS parsing is complex, we fall back to null
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function buildAffectedVersionsString(vuln) {
|
|
61
|
+
const affected = vuln.affected;
|
|
62
|
+
if (!affected || affected.length === 0)
|
|
63
|
+
return 'See advisory for details';
|
|
64
|
+
const versions = [];
|
|
65
|
+
for (const entry of affected) {
|
|
66
|
+
if (entry.versions && entry.versions.length > 0) {
|
|
67
|
+
versions.push(...entry.versions.slice(0, 5));
|
|
68
|
+
if (entry.versions.length > 5) {
|
|
69
|
+
versions.push(`... and ${entry.versions.length - 5} more`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (entry.ranges) {
|
|
73
|
+
for (const range of entry.ranges) {
|
|
74
|
+
if (range.events) {
|
|
75
|
+
const parts = [];
|
|
76
|
+
for (const event of range.events) {
|
|
77
|
+
const introduced = event['introduced'];
|
|
78
|
+
const fixed = event['fixed'];
|
|
79
|
+
if (introduced !== undefined)
|
|
80
|
+
parts.push(`>= ${introduced}`);
|
|
81
|
+
if (fixed !== undefined)
|
|
82
|
+
parts.push(`< ${fixed}`);
|
|
83
|
+
}
|
|
84
|
+
if (parts.length > 0)
|
|
85
|
+
versions.push(parts.join(', '));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return versions.length > 0 ? versions.join('; ') : 'See advisory for details';
|
|
91
|
+
}
|
|
92
|
+
// ─── Analyzer ─────────────────────────────────────────────
|
|
93
|
+
export class VulnerabilityAnalyzer {
|
|
94
|
+
name = 'vulnerability-scanner';
|
|
95
|
+
description = 'Checks for known CVEs and security advisories via the OSV database';
|
|
96
|
+
async analyze(context) {
|
|
97
|
+
const start = performance.now();
|
|
98
|
+
const findings = [];
|
|
99
|
+
try {
|
|
100
|
+
const requestBody = {
|
|
101
|
+
package: {
|
|
102
|
+
name: context.packageName,
|
|
103
|
+
ecosystem: 'npm',
|
|
104
|
+
},
|
|
105
|
+
version: context.version,
|
|
106
|
+
};
|
|
107
|
+
const result = await fetchJson(OSV_API_URL, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
110
|
+
body: JSON.stringify(requestBody),
|
|
111
|
+
timeout: 15_000,
|
|
112
|
+
});
|
|
113
|
+
if (!result.ok) {
|
|
114
|
+
// API error — return empty findings, don't crash
|
|
115
|
+
logger.warn(`[${this.name}] OSV API error: ${result.message} (${result.error})`);
|
|
116
|
+
return {
|
|
117
|
+
analyzer: this.name,
|
|
118
|
+
findings: [],
|
|
119
|
+
duration: performance.now() - start,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const vulns = result.data.vulns ?? [];
|
|
123
|
+
for (const vuln of vulns) {
|
|
124
|
+
const cveId = extractCveId(vuln);
|
|
125
|
+
const severity = mapOsvSeverity(vuln);
|
|
126
|
+
const summary = vuln.summary ?? vuln.details ?? 'No description available';
|
|
127
|
+
const affectedVersions = buildAffectedVersionsString(vuln);
|
|
128
|
+
findings.push({
|
|
129
|
+
analyzer: this.name,
|
|
130
|
+
severity,
|
|
131
|
+
title: `${cveId} in ${context.packageName}@${context.version}`,
|
|
132
|
+
description: summary,
|
|
133
|
+
recommendation: `Upgrade to a non-affected version. Affected: ${affectedVersions}`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
logger.warn(`[${this.name}] Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
analyzer: this.name,
|
|
142
|
+
findings,
|
|
143
|
+
duration: performance.now() - start,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzers/vulnerability/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "check" command handler.
|
|
3
|
+
*
|
|
4
|
+
* Parses package specifiers, fetches metadata and tarballs from the
|
|
5
|
+
* npm registry, runs the analysis engine, and outputs formatted results.
|
|
6
|
+
*/
|
|
7
|
+
import type { CheckOptions } from '../../core/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Execute the "check" command for one or more packages.
|
|
10
|
+
*
|
|
11
|
+
* For each package:
|
|
12
|
+
* 1. Fetch metadata from npm registry
|
|
13
|
+
* 2. Download and extract tarball to temp directory
|
|
14
|
+
* 3. Run all analyzers via the engine
|
|
15
|
+
* 4. Format and output results
|
|
16
|
+
*
|
|
17
|
+
* Returns true if all packages pass (no findings at or above --fail-on),
|
|
18
|
+
* false if any package fails the threshold check.
|
|
19
|
+
*/
|
|
20
|
+
export declare function executeCheck(options: CheckOptions): Promise<boolean>;
|
|
21
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,OAAO,KAAK,EAEV,YAAY,EAIb,MAAM,qBAAqB,CAAC;AA0E7B;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAuI1E"}
|