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.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -0
  3. package/dist/analyzers/analyzer.interface.d.ts +32 -0
  4. package/dist/analyzers/analyzer.interface.d.ts.map +1 -0
  5. package/dist/analyzers/analyzer.interface.js +2 -0
  6. package/dist/analyzers/analyzer.interface.js.map +1 -0
  7. package/dist/analyzers/analyzer.registry.d.ts +16 -0
  8. package/dist/analyzers/analyzer.registry.d.ts.map +1 -0
  9. package/dist/analyzers/analyzer.registry.js +40 -0
  10. package/dist/analyzers/analyzer.registry.js.map +1 -0
  11. package/dist/analyzers/dependency-confusion/index.d.ts +14 -0
  12. package/dist/analyzers/dependency-confusion/index.d.ts.map +1 -0
  13. package/dist/analyzers/dependency-confusion/index.js +147 -0
  14. package/dist/analyzers/dependency-confusion/index.js.map +1 -0
  15. package/dist/analyzers/dormant-package/index.d.ts +14 -0
  16. package/dist/analyzers/dormant-package/index.d.ts.map +1 -0
  17. package/dist/analyzers/dormant-package/index.js +137 -0
  18. package/dist/analyzers/dormant-package/index.js.map +1 -0
  19. package/dist/analyzers/file-based-analyzer.d.ts +20 -0
  20. package/dist/analyzers/file-based-analyzer.d.ts.map +1 -0
  21. package/dist/analyzers/file-based-analyzer.js +35 -0
  22. package/dist/analyzers/file-based-analyzer.js.map +1 -0
  23. package/dist/analyzers/install-scripts/index.d.ts +13 -0
  24. package/dist/analyzers/install-scripts/index.d.ts.map +1 -0
  25. package/dist/analyzers/install-scripts/index.js +125 -0
  26. package/dist/analyzers/install-scripts/index.js.map +1 -0
  27. package/dist/analyzers/license/index.d.ts +12 -0
  28. package/dist/analyzers/license/index.d.ts.map +1 -0
  29. package/dist/analyzers/license/index.js +199 -0
  30. package/dist/analyzers/license/index.js.map +1 -0
  31. package/dist/analyzers/maintainer/index.d.ts +12 -0
  32. package/dist/analyzers/maintainer/index.d.ts.map +1 -0
  33. package/dist/analyzers/maintainer/index.js +93 -0
  34. package/dist/analyzers/maintainer/index.js.map +1 -0
  35. package/dist/analyzers/network-calls/index.d.ts +15 -0
  36. package/dist/analyzers/network-calls/index.d.ts.map +1 -0
  37. package/dist/analyzers/network-calls/index.js +212 -0
  38. package/dist/analyzers/network-calls/index.js.map +1 -0
  39. package/dist/analyzers/obfuscation/index.d.ts +19 -0
  40. package/dist/analyzers/obfuscation/index.d.ts.map +1 -0
  41. package/dist/analyzers/obfuscation/index.js +218 -0
  42. package/dist/analyzers/obfuscation/index.js.map +1 -0
  43. package/dist/analyzers/prototype-pollution/index.d.ts +18 -0
  44. package/dist/analyzers/prototype-pollution/index.d.ts.map +1 -0
  45. package/dist/analyzers/prototype-pollution/index.js +257 -0
  46. package/dist/analyzers/prototype-pollution/index.js.map +1 -0
  47. package/dist/analyzers/sensitive-data/index.d.ts +16 -0
  48. package/dist/analyzers/sensitive-data/index.d.ts.map +1 -0
  49. package/dist/analyzers/sensitive-data/index.js +254 -0
  50. package/dist/analyzers/sensitive-data/index.js.map +1 -0
  51. package/dist/analyzers/typosquatting/index.d.ts +14 -0
  52. package/dist/analyzers/typosquatting/index.d.ts.map +1 -0
  53. package/dist/analyzers/typosquatting/index.js +127 -0
  54. package/dist/analyzers/typosquatting/index.js.map +1 -0
  55. package/dist/analyzers/typosquatting/popular-packages.d.ts +9 -0
  56. package/dist/analyzers/typosquatting/popular-packages.d.ts.map +1 -0
  57. package/dist/analyzers/typosquatting/popular-packages.js +236 -0
  58. package/dist/analyzers/typosquatting/popular-packages.js.map +1 -0
  59. package/dist/analyzers/vulnerability/index.d.ts +12 -0
  60. package/dist/analyzers/vulnerability/index.d.ts.map +1 -0
  61. package/dist/analyzers/vulnerability/index.js +147 -0
  62. package/dist/analyzers/vulnerability/index.js.map +1 -0
  63. package/dist/cli/commands/check.d.ts +21 -0
  64. package/dist/cli/commands/check.d.ts.map +1 -0
  65. package/dist/cli/commands/check.js +204 -0
  66. package/dist/cli/commands/check.js.map +1 -0
  67. package/dist/cli/formatters/formatter.interface.d.ts +14 -0
  68. package/dist/cli/formatters/formatter.interface.d.ts.map +1 -0
  69. package/dist/cli/formatters/formatter.interface.js +2 -0
  70. package/dist/cli/formatters/formatter.interface.js.map +1 -0
  71. package/dist/cli/formatters/json.d.ts +12 -0
  72. package/dist/cli/formatters/json.d.ts.map +1 -0
  73. package/dist/cli/formatters/json.js +12 -0
  74. package/dist/cli/formatters/json.js.map +1 -0
  75. package/dist/cli/formatters/sarif.d.ts +13 -0
  76. package/dist/cli/formatters/sarif.d.ts.map +1 -0
  77. package/dist/cli/formatters/sarif.js +101 -0
  78. package/dist/cli/formatters/sarif.js.map +1 -0
  79. package/dist/cli/formatters/terminal.d.ts +13 -0
  80. package/dist/cli/formatters/terminal.d.ts.map +1 -0
  81. package/dist/cli/formatters/terminal.js +110 -0
  82. package/dist/cli/formatters/terminal.js.map +1 -0
  83. package/dist/cli/index.d.ts +9 -0
  84. package/dist/cli/index.d.ts.map +1 -0
  85. package/dist/cli/index.js +86 -0
  86. package/dist/cli/index.js.map +1 -0
  87. package/dist/core/engine.d.ts +23 -0
  88. package/dist/core/engine.d.ts.map +1 -0
  89. package/dist/core/engine.js +55 -0
  90. package/dist/core/engine.js.map +1 -0
  91. package/dist/core/scorer.d.ts +30 -0
  92. package/dist/core/scorer.d.ts.map +1 -0
  93. package/dist/core/scorer.js +88 -0
  94. package/dist/core/scorer.js.map +1 -0
  95. package/dist/core/types.d.ts +76 -0
  96. package/dist/core/types.d.ts.map +1 -0
  97. package/dist/core/types.js +30 -0
  98. package/dist/core/types.js.map +1 -0
  99. package/dist/index.d.ts +33 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +30 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/registry/client.d.ts +27 -0
  104. package/dist/registry/client.d.ts.map +1 -0
  105. package/dist/registry/client.js +189 -0
  106. package/dist/registry/client.js.map +1 -0
  107. package/dist/registry/tarball.d.ts +34 -0
  108. package/dist/registry/tarball.d.ts.map +1 -0
  109. package/dist/registry/tarball.js +103 -0
  110. package/dist/registry/tarball.js.map +1 -0
  111. package/dist/utils/ast.d.ts +74 -0
  112. package/dist/utils/ast.d.ts.map +1 -0
  113. package/dist/utils/ast.js +150 -0
  114. package/dist/utils/ast.js.map +1 -0
  115. package/dist/utils/fs.d.ts +28 -0
  116. package/dist/utils/fs.d.ts.map +1 -0
  117. package/dist/utils/fs.js +78 -0
  118. package/dist/utils/fs.js.map +1 -0
  119. package/dist/utils/http.d.ts +40 -0
  120. package/dist/utils/http.d.ts.map +1 -0
  121. package/dist/utils/http.js +116 -0
  122. package/dist/utils/http.js.map +1 -0
  123. package/dist/utils/logger.d.ts +46 -0
  124. package/dist/utils/logger.d.ts.map +1 -0
  125. package/dist/utils/logger.js +91 -0
  126. package/dist/utils/logger.js.map +1 -0
  127. package/dist/utils/strings.d.ts +8 -0
  128. package/dist/utils/strings.d.ts.map +1 -0
  129. package/dist/utils/strings.js +12 -0
  130. package/dist/utils/strings.js.map +1 -0
  131. package/package.json +96 -0
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Prototype Pollution Analyzer — detects __proto__ access, Object.prototype
3
+ * mutation, constructor.prototype patterns, and recursive merge/extend
4
+ * functions without hasOwnProperty guards.
5
+ */
6
+ import { parseSource, walkAST, getNodeLine, optionalLine } from '../../utils/ast.js';
7
+ import { FileBasedAnalyzer } from '../file-based-analyzer.js';
8
+ // ─── Constants ────────────────────────────────────────────
9
+ /** Names commonly used for recursive merge/extend/assign functions. */
10
+ const MERGE_FUNCTION_NAMES = new Set([
11
+ 'merge',
12
+ 'deepMerge',
13
+ 'deep_merge',
14
+ 'deepmerge',
15
+ 'extend',
16
+ 'deepExtend',
17
+ 'deep_extend',
18
+ 'assign',
19
+ 'deepAssign',
20
+ 'deep_assign',
21
+ 'mixin',
22
+ 'defaults',
23
+ 'deepDefaults',
24
+ 'setPath',
25
+ 'setNested',
26
+ 'set',
27
+ ]);
28
+ // ─── Analyzer ─────────────────────────────────────────────
29
+ export class PrototypePollutionAnalyzer extends FileBasedAnalyzer {
30
+ name = 'prototype-pollution';
31
+ description = 'Detects prototype pollution vectors including __proto__ access and unsafe merge patterns';
32
+ analyzeFile(source, relPath) {
33
+ const findings = [];
34
+ findings.push(...this.detectProtoAccess(source, relPath));
35
+ findings.push(...this.detectPrototypeMutation(source, relPath));
36
+ findings.push(...this.detectConstructorPrototype(source, relPath));
37
+ findings.push(...this.detectUnsafeMerge(source, relPath));
38
+ return findings;
39
+ }
40
+ detectProtoAccess(source, relPath) {
41
+ const findings = [];
42
+ const parsed = parseSource(source, relPath);
43
+ if (!parsed.ok)
44
+ return findings;
45
+ walkAST(parsed.ast, (node) => {
46
+ if (node.type === 'MemberExpression') {
47
+ const property = node['property'];
48
+ if (property?.['type'] === 'Identifier' && property['name'] === '__proto__') {
49
+ findings.push({
50
+ analyzer: this.name,
51
+ severity: 'high',
52
+ title: '__proto__ property access',
53
+ description: 'Direct access to __proto__ can be used for prototype pollution attacks.',
54
+ file: relPath,
55
+ ...optionalLine(getNodeLine(node)),
56
+ recommendation: 'Avoid __proto__ usage. Use Object.getPrototypeOf() / Object.setPrototypeOf() if needed.',
57
+ });
58
+ }
59
+ if (node['computed'] === true &&
60
+ property?.['type'] === 'Literal' &&
61
+ property['value'] === '__proto__') {
62
+ findings.push({
63
+ analyzer: this.name,
64
+ severity: 'high',
65
+ title: '__proto__ computed property access',
66
+ description: 'Computed access to "__proto__" via bracket notation, a common prototype pollution vector.',
67
+ file: relPath,
68
+ ...optionalLine(getNodeLine(node)),
69
+ recommendation: 'Sanitize property keys to exclude "__proto__".',
70
+ });
71
+ }
72
+ }
73
+ if (node.type === 'Property') {
74
+ const key = node['key'];
75
+ if ((key?.['type'] === 'Identifier' && key['name'] === '__proto__') ||
76
+ (key?.['type'] === 'Literal' && key['value'] === '__proto__')) {
77
+ findings.push({
78
+ analyzer: this.name,
79
+ severity: 'high',
80
+ title: '__proto__ property definition',
81
+ description: 'An object literal defines a "__proto__" property, which can pollute the prototype chain.',
82
+ file: relPath,
83
+ ...optionalLine(getNodeLine(node)),
84
+ recommendation: 'Avoid defining __proto__ in object literals.',
85
+ });
86
+ }
87
+ }
88
+ });
89
+ return findings;
90
+ }
91
+ detectPrototypeMutation(source, relPath) {
92
+ const findings = [];
93
+ const parsed = parseSource(source, relPath);
94
+ if (!parsed.ok)
95
+ return findings;
96
+ walkAST(parsed.ast, (node) => {
97
+ if (node.type !== 'AssignmentExpression')
98
+ return;
99
+ const left = node['left'];
100
+ if (left?.['type'] !== 'MemberExpression')
101
+ return;
102
+ const object = left['object'];
103
+ if (object?.['type'] !== 'MemberExpression')
104
+ return;
105
+ const outerObj = object['object'];
106
+ const outerProp = object['property'];
107
+ if (outerObj?.['type'] === 'Identifier' &&
108
+ outerProp?.['type'] === 'Identifier' &&
109
+ outerProp['name'] === 'prototype') {
110
+ const targetName = outerObj['name'];
111
+ if (targetName === 'Object' || targetName === 'Array') {
112
+ findings.push({
113
+ analyzer: this.name,
114
+ severity: 'high',
115
+ title: `${targetName}.prototype mutation detected`,
116
+ description: `Assignment to ${targetName}.prototype modifies the prototype of all ${targetName} instances, ` +
117
+ 'which can lead to prototype pollution affecting the entire runtime.',
118
+ file: relPath,
119
+ ...optionalLine(getNodeLine(node)),
120
+ recommendation: `Avoid modifying ${targetName}.prototype. Use utility functions or classes instead.`,
121
+ });
122
+ }
123
+ }
124
+ });
125
+ return findings;
126
+ }
127
+ detectConstructorPrototype(source, relPath) {
128
+ const findings = [];
129
+ const parsed = parseSource(source, relPath);
130
+ if (!parsed.ok)
131
+ return findings;
132
+ walkAST(parsed.ast, (node) => {
133
+ if (node.type !== 'MemberExpression')
134
+ return;
135
+ const property = node['property'];
136
+ if (property?.['type'] !== 'Identifier' || property['name'] !== 'prototype')
137
+ return;
138
+ const object = node['object'];
139
+ if (object?.['type'] !== 'MemberExpression')
140
+ return;
141
+ const innerProp = object['property'];
142
+ if (innerProp?.['type'] === 'Identifier' && innerProp['name'] === 'constructor') {
143
+ findings.push({
144
+ analyzer: this.name,
145
+ severity: 'medium',
146
+ title: 'constructor.prototype access pattern',
147
+ description: 'Access to constructor.prototype can be used to traverse and mutate the prototype chain.',
148
+ file: relPath,
149
+ ...optionalLine(getNodeLine(node)),
150
+ recommendation: 'Review whether this pattern is used safely.',
151
+ });
152
+ }
153
+ });
154
+ return findings;
155
+ }
156
+ detectUnsafeMerge(source, relPath) {
157
+ const findings = [];
158
+ const parsed = parseSource(source, relPath);
159
+ if (!parsed.ok)
160
+ return findings;
161
+ walkAST(parsed.ast, (node) => {
162
+ if (node.type === 'FunctionDeclaration') {
163
+ const id = node['id'];
164
+ if (id?.['type'] === 'Identifier' && typeof id['name'] === 'string') {
165
+ const fnName = id['name'];
166
+ if (MERGE_FUNCTION_NAMES.has(fnName)) {
167
+ const hasGuard = this.bodyHasOwnPropertyGuard(node['body']);
168
+ if (!hasGuard) {
169
+ findings.push({
170
+ analyzer: this.name,
171
+ severity: 'medium',
172
+ title: `Potentially unsafe merge function: ${fnName}()`,
173
+ description: `Function "${fnName}" is a merge/extend function without a hasOwnProperty check. ` +
174
+ 'This may allow prototype pollution through attacker-controlled input.',
175
+ file: relPath,
176
+ ...optionalLine(getNodeLine(node)),
177
+ recommendation: 'Add hasOwnProperty checks or use Object.keys()/Object.entries() to iterate safely. ' +
178
+ 'Also filter out "__proto__", "constructor", and "prototype" keys.',
179
+ });
180
+ }
181
+ }
182
+ }
183
+ }
184
+ if (node.type === 'VariableDeclaration') {
185
+ const declarations = node['declarations'];
186
+ if (!Array.isArray(declarations))
187
+ return;
188
+ for (const decl of declarations) {
189
+ const declNode = decl;
190
+ if (declNode['type'] !== 'VariableDeclarator')
191
+ continue;
192
+ const id = declNode['id'];
193
+ const init = declNode['init'];
194
+ if (id?.['type'] === 'Identifier' &&
195
+ typeof id['name'] === 'string' &&
196
+ MERGE_FUNCTION_NAMES.has(id['name']) &&
197
+ init !== undefined &&
198
+ (init['type'] === 'ArrowFunctionExpression' || init['type'] === 'FunctionExpression')) {
199
+ const hasGuard = this.bodyHasOwnPropertyGuard(init['body']);
200
+ if (!hasGuard) {
201
+ findings.push({
202
+ analyzer: this.name,
203
+ severity: 'medium',
204
+ title: `Potentially unsafe merge function: ${String(id['name'])}()`,
205
+ description: `Function "${String(id['name'])}" appears to be a merge/extend function without ` +
206
+ 'a hasOwnProperty check, which may allow prototype pollution.',
207
+ file: relPath,
208
+ ...optionalLine(getNodeLine(node)),
209
+ recommendation: 'Add hasOwnProperty checks and filter dangerous keys like "__proto__".',
210
+ });
211
+ }
212
+ }
213
+ }
214
+ }
215
+ });
216
+ return findings;
217
+ }
218
+ bodyHasOwnPropertyGuard(body) {
219
+ if (typeof body !== 'object' || body === null)
220
+ return false;
221
+ let found = false;
222
+ walkAST(body, (node) => {
223
+ if (found)
224
+ return false;
225
+ if (node.type === 'CallExpression') {
226
+ const callee = node['callee'];
227
+ if (callee?.['type'] === 'MemberExpression') {
228
+ const prop = callee['property'];
229
+ if (prop?.['type'] === 'Identifier' && prop['name'] === 'hasOwnProperty') {
230
+ found = true;
231
+ return false;
232
+ }
233
+ // Object.hasOwn()
234
+ const obj = callee['object'];
235
+ if (obj?.['type'] === 'Identifier' &&
236
+ obj['name'] === 'Object' &&
237
+ prop?.['type'] === 'Identifier' &&
238
+ prop['name'] === 'hasOwn') {
239
+ found = true;
240
+ return false;
241
+ }
242
+ // Object.keys() / Object.entries()
243
+ if (obj?.['type'] === 'Identifier' &&
244
+ obj['name'] === 'Object' &&
245
+ prop?.['type'] === 'Identifier' &&
246
+ (prop['name'] === 'keys' || prop['name'] === 'entries')) {
247
+ found = true;
248
+ return false;
249
+ }
250
+ }
251
+ }
252
+ return undefined;
253
+ });
254
+ return found;
255
+ }
256
+ }
257
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzers/prototype-pollution/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Sensitive Data Analyzer — detects access to environment variables,
3
+ * credential files, sensitive filesystem paths, and secret key files.
4
+ */
5
+ import type { Finding } from '../../core/types.js';
6
+ import { FileBasedAnalyzer } from '../file-based-analyzer.js';
7
+ export declare class SensitiveDataAnalyzer extends FileBasedAnalyzer {
8
+ readonly name = "sensitive-data";
9
+ readonly description = "Detects access to environment variables, credentials, and sensitive file paths";
10
+ protected analyzeFile(source: string, relPath: string): Finding[];
11
+ private detectProcessEnvAccess;
12
+ private detectSensitivePaths;
13
+ private detectSensitiveFilePatterns;
14
+ private detectEnvHarvesting;
15
+ }
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyzers/sensitive-data/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAuD9D,qBAAa,qBAAsB,SAAQ,iBAAiB;IAC1D,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,WAAW,oFAC+D;IAEnF,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE;IAWjE,OAAO,CAAC,sBAAsB;IAkI9B,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,2BAA2B;IA0BnC,OAAO,CAAC,mBAAmB;CAmC5B"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Sensitive Data Analyzer — detects access to environment variables,
3
+ * credential files, sensitive filesystem paths, and secret key files.
4
+ */
5
+ import { parseSource, walkAST, extractStringLiterals, isMemberAccess } from '../../utils/ast.js';
6
+ import { truncate } from '../../utils/strings.js';
7
+ import { FileBasedAnalyzer } from '../file-based-analyzer.js';
8
+ // ─── Constants ────────────────────────────────────────────
9
+ /** Sensitive filesystem paths. */
10
+ const SENSITIVE_PATHS = [
11
+ '~/.ssh',
12
+ '~/.aws',
13
+ '~/.npmrc',
14
+ '~/.gnupg',
15
+ '~/.config',
16
+ '~/.netrc',
17
+ '~/.bash_history',
18
+ '~/.zsh_history',
19
+ '/etc/passwd',
20
+ '/etc/shadow',
21
+ '/etc/hosts',
22
+ '.env',
23
+ '.env.local',
24
+ '.env.production',
25
+ ];
26
+ /** File patterns that commonly contain secrets. */
27
+ const SENSITIVE_FILE_PATTERNS = [
28
+ /\.pem$/i,
29
+ /\.key$/i,
30
+ /\bid_rsa\b/i,
31
+ /\bid_ed25519\b/i,
32
+ /\bid_ecdsa\b/i,
33
+ /\bcredentials\.json\b/i,
34
+ /\bservice[_-]?account\.json\b/i,
35
+ /\b\.env\b/,
36
+ /\btoken\.json\b/i,
37
+ /\bsecrets?\.(json|ya?ml|toml)\b/i,
38
+ /\bkeystore\b/i,
39
+ /\bknown_hosts\b/i,
40
+ ];
41
+ /** Sensitive-sounding environment variable name fragments. */
42
+ const SENSITIVE_ENV_NAMES = [
43
+ 'SECRET',
44
+ 'TOKEN',
45
+ 'API_KEY',
46
+ 'APIKEY',
47
+ 'PASSWORD',
48
+ 'PASSWD',
49
+ 'PRIVATE_KEY',
50
+ 'ACCESS_KEY',
51
+ 'AWS_SECRET',
52
+ 'DATABASE_URL',
53
+ 'DB_PASSWORD',
54
+ ];
55
+ // ─── Analyzer ─────────────────────────────────────────────
56
+ export class SensitiveDataAnalyzer extends FileBasedAnalyzer {
57
+ name = 'sensitive-data';
58
+ description = 'Detects access to environment variables, credentials, and sensitive file paths';
59
+ analyzeFile(source, relPath) {
60
+ const findings = [];
61
+ findings.push(...this.detectProcessEnvAccess(source, relPath));
62
+ findings.push(...this.detectSensitivePaths(source, relPath));
63
+ findings.push(...this.detectSensitiveFilePatterns(source, relPath));
64
+ findings.push(...this.detectEnvHarvesting(source, relPath));
65
+ return findings;
66
+ }
67
+ detectProcessEnvAccess(source, relPath) {
68
+ const findings = [];
69
+ const parsed = parseSource(source, relPath);
70
+ if (!parsed.ok)
71
+ return findings;
72
+ let envAccessCount = 0;
73
+ const state = { bulkEnvAccess: false };
74
+ walkAST(parsed.ast, (node) => {
75
+ // process.env
76
+ if (isMemberAccess(node, 'process', 'env')) {
77
+ envAccessCount++;
78
+ // Check if this is the object in a further member expression (process.env.SECRET_KEY)
79
+ // We count them; too many distinct env accesses is suspicious
80
+ }
81
+ // Object.keys(process.env) or Object.entries(process.env) — bulk harvesting
82
+ if (node.type === 'CallExpression') {
83
+ const callee = node['callee'];
84
+ if (typeof callee === 'object' && callee !== null) {
85
+ const calleeNode = callee;
86
+ if (calleeNode['type'] === 'MemberExpression') {
87
+ const obj = calleeNode['object'];
88
+ const prop = calleeNode['property'];
89
+ if (obj?.['type'] === 'Identifier' &&
90
+ obj['name'] === 'Object' &&
91
+ prop?.['type'] === 'Identifier' &&
92
+ (prop['name'] === 'keys' || prop['name'] === 'entries' || prop['name'] === 'values')) {
93
+ const args = node['arguments'];
94
+ if (Array.isArray(args) && args.length > 0) {
95
+ const firstArg = args[0];
96
+ if (firstArg?.['type'] === 'MemberExpression' &&
97
+ typeof firstArg['object'] === 'object' &&
98
+ firstArg['object'] !== null) {
99
+ const argObj = firstArg['object'];
100
+ const argProp = firstArg['property'];
101
+ if (argObj['type'] === 'Identifier' &&
102
+ argObj['name'] === 'process' &&
103
+ argProp?.['type'] === 'Identifier' &&
104
+ argProp['name'] === 'env') {
105
+ state.bulkEnvAccess = true;
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ // JSON.stringify(process.env)
114
+ if (node.type === 'CallExpression') {
115
+ const callee = node['callee'];
116
+ if (typeof callee === 'object' && callee !== null) {
117
+ const calleeNode = callee;
118
+ if (calleeNode['type'] === 'MemberExpression') {
119
+ const obj = calleeNode['object'];
120
+ const prop = calleeNode['property'];
121
+ if (obj?.['type'] === 'Identifier' &&
122
+ obj['name'] === 'JSON' &&
123
+ prop?.['type'] === 'Identifier' &&
124
+ prop['name'] === 'stringify') {
125
+ const args = node['arguments'];
126
+ if (Array.isArray(args) && args.length > 0) {
127
+ const firstArg = args[0];
128
+ if (firstArg?.['type'] === 'MemberExpression' &&
129
+ typeof firstArg['object'] === 'object' &&
130
+ firstArg['object'] !== null) {
131
+ const argObj = firstArg['object'];
132
+ const argProp = firstArg['property'];
133
+ if (argObj['type'] === 'Identifier' &&
134
+ argObj['name'] === 'process' &&
135
+ argProp?.['type'] === 'Identifier' &&
136
+ argProp['name'] === 'env') {
137
+ state.bulkEnvAccess = true;
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ });
146
+ if (state.bulkEnvAccess) {
147
+ findings.push({
148
+ analyzer: this.name,
149
+ severity: 'high',
150
+ title: 'Bulk environment variable harvesting detected',
151
+ description: 'The package accesses the entire process.env object (via Object.keys, Object.entries, or JSON.stringify). ' +
152
+ 'This may be used to exfiltrate secrets.',
153
+ file: relPath,
154
+ recommendation: 'Investigate what the package does with the full environment.',
155
+ });
156
+ }
157
+ else if (envAccessCount > 5) {
158
+ findings.push({
159
+ analyzer: this.name,
160
+ severity: 'high',
161
+ title: `Excessive process.env access (${envAccessCount} occurrences)`,
162
+ description: `The package accesses process.env ${envAccessCount} times, which may indicate environment harvesting.`,
163
+ file: relPath,
164
+ recommendation: 'Review which environment variables are being read and why.',
165
+ });
166
+ }
167
+ else if (envAccessCount > 0) {
168
+ findings.push({
169
+ analyzer: this.name,
170
+ severity: 'info',
171
+ title: `process.env access detected (${envAccessCount} occurrences)`,
172
+ description: `The package reads environment variables (${envAccessCount} access points).`,
173
+ file: relPath,
174
+ recommendation: 'Verify the package only reads expected configuration variables.',
175
+ });
176
+ }
177
+ return findings;
178
+ }
179
+ detectSensitivePaths(source, relPath) {
180
+ const findings = [];
181
+ const strings = extractStringLiterals(source, relPath);
182
+ const flagged = new Set();
183
+ for (const str of strings) {
184
+ for (const sensitivePath of SENSITIVE_PATHS) {
185
+ if (str.includes(sensitivePath) && !flagged.has(sensitivePath)) {
186
+ flagged.add(sensitivePath);
187
+ findings.push({
188
+ analyzer: this.name,
189
+ severity: 'critical',
190
+ title: `Access to sensitive path: ${sensitivePath}`,
191
+ description: `The package contains a reference to "${sensitivePath}", ` +
192
+ 'which may indicate credential theft or reconnaissance.',
193
+ file: relPath,
194
+ recommendation: 'Investigate why the package accesses this sensitive path.',
195
+ });
196
+ }
197
+ }
198
+ }
199
+ return findings;
200
+ }
201
+ detectSensitiveFilePatterns(source, relPath) {
202
+ const findings = [];
203
+ const strings = extractStringLiterals(source, relPath);
204
+ const flagged = new Set();
205
+ for (const str of strings) {
206
+ for (const pattern of SENSITIVE_FILE_PATTERNS) {
207
+ if (pattern.test(str) && !flagged.has(str)) {
208
+ flagged.add(str);
209
+ findings.push({
210
+ analyzer: this.name,
211
+ severity: 'critical',
212
+ title: `Credential file reference: ${truncate(str, 60)}`,
213
+ description: `The package references a file matching sensitive credential pattern: "${truncate(str, 120)}".`,
214
+ file: relPath,
215
+ recommendation: 'Verify why the package needs access to credential files.',
216
+ });
217
+ break; // Only match first pattern per string
218
+ }
219
+ }
220
+ }
221
+ return findings;
222
+ }
223
+ detectEnvHarvesting(source, relPath) {
224
+ const findings = [];
225
+ const strings = extractStringLiterals(source, relPath);
226
+ const foundSensitiveEnvs = [];
227
+ for (const str of strings) {
228
+ const upperStr = str.toUpperCase();
229
+ for (const envName of SENSITIVE_ENV_NAMES) {
230
+ if (upperStr.includes(envName)) {
231
+ foundSensitiveEnvs.push(str);
232
+ break;
233
+ }
234
+ }
235
+ }
236
+ // Only flag if process.env is also accessed
237
+ if (foundSensitiveEnvs.length > 0 && source.includes('process.env')) {
238
+ findings.push({
239
+ analyzer: this.name,
240
+ severity: 'high',
241
+ title: 'Sensitive environment variable names detected',
242
+ description: `The package references sensitive-sounding env variable names: ` +
243
+ `${foundSensitiveEnvs
244
+ .slice(0, 5)
245
+ .map((s) => `"${s}"`)
246
+ .join(', ')}`,
247
+ file: relPath,
248
+ recommendation: 'Verify the package is not exfiltrating secret values.',
249
+ });
250
+ }
251
+ return findings;
252
+ }
253
+ }
254
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzers/sensitive-data/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
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 type { Analyzer } from '../analyzer.interface.js';
7
+ import type { AnalysisContext, AnalyzerResult } from '../../core/types.js';
8
+ export declare class TyposquattingAnalyzer implements Analyzer {
9
+ readonly name = "typosquatting";
10
+ readonly description = "Detects package names that may be typosquatting popular npm packages";
11
+ analyze(context: AnalysisContext): Promise<AnalyzerResult>;
12
+ private createFinding;
13
+ }
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyzers/typosquatting/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAqB,MAAM,qBAAqB,CAAC;AAsE9F,qBAAa,qBAAsB,YAAW,QAAQ;IACpD,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,WAAW,0EAA0E;IAE9F,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAkE1D,OAAO,CAAC,aAAa;CAgBtB"}