muaddib-scanner 1.0.9 → 1.0.11

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 (33) hide show
  1. package/.muaddib-cache/iocs.json +355 -0
  2. package/package.json +3 -3
  3. package/rapport.html +159 -0
  4. package/src/scanner/ast.js +45 -14
  5. package/src/scanner/dataflow.js +39 -11
  6. package/src/scanner/typosquat.js +97 -140
  7. package/.github/workflows/scan.yml +0 -33
  8. package/CONTRIBUTING.md +0 -98
  9. package/docs/threat-model.md +0 -116
  10. package/test/samples/malicious.js +0 -20
  11. package/tests/run-tests.js +0 -389
  12. package/tests/samples/ast/malicious.js +0 -20
  13. package/tests/samples/clean/safe.js +0 -14
  14. package/tests/samples/dataflow/exfiltration.js +0 -20
  15. package/tests/samples/edge/empty/empty.js +0 -0
  16. package/tests/samples/edge/invalid-syntax/broken.js +0 -5
  17. package/tests/samples/edge/large-file/large.js +0 -6
  18. package/tests/samples/edge/non-js/readme.txt +0 -3
  19. package/tests/samples/markers/shai-hulud.js +0 -10
  20. package/tests/samples/obfuscation/obfuscated.js +0 -1
  21. package/tests/samples/package/package.json +0 -9
  22. package/tests/samples/shell/malicious.sh +0 -13
  23. package/tests/samples/typosquat/package.json +0 -11
  24. package/vscode-extension/.vscode/launch.json +0 -13
  25. package/vscode-extension/.vscodeignore +0 -0
  26. package/vscode-extension/LICENSE +0 -21
  27. package/vscode-extension/README.md +0 -0
  28. package/vscode-extension/extension.js +0 -271
  29. package/vscode-extension/icon.png +0 -0
  30. package/vscode-extension/muaddib-vscode-1.0.0.vsix +0 -0
  31. package/vscode-extension/package.json +0 -69
  32. package/vscode-extension/vscode-extension/README.md +0 -44
  33. package/vscode-extension/vscode-extension/package.json +0 -64
@@ -0,0 +1,355 @@
1
+ {
2
+ "packages": [
3
+ {
4
+ "name": "@ctrl/tinycolor",
5
+ "version": "4.1.1",
6
+ "source": "shai-hulud-v1"
7
+ },
8
+ {
9
+ "name": "ng2-file-upload",
10
+ "version": "*",
11
+ "source": "shai-hulud-v1"
12
+ },
13
+ {
14
+ "name": "ngx-bootstrap",
15
+ "version": "*",
16
+ "source": "shai-hulud-v1"
17
+ },
18
+ {
19
+ "name": "@asyncapi/specs",
20
+ "version": "*",
21
+ "source": "shai-hulud-v2"
22
+ },
23
+ {
24
+ "name": "@asyncapi/openapi-schema-parser",
25
+ "version": "*",
26
+ "source": "shai-hulud-v2"
27
+ },
28
+ {
29
+ "name": "get-them-args",
30
+ "version": "*",
31
+ "source": "shai-hulud-v2"
32
+ },
33
+ {
34
+ "name": "kill-port",
35
+ "version": "*",
36
+ "source": "shai-hulud-v2"
37
+ },
38
+ {
39
+ "name": "shell-exec",
40
+ "version": "*",
41
+ "source": "shai-hulud-v2"
42
+ },
43
+ {
44
+ "name": "posthog-node",
45
+ "version": "*",
46
+ "source": "shai-hulud-v2"
47
+ },
48
+ {
49
+ "name": "posthog-js",
50
+ "version": "*",
51
+ "source": "shai-hulud-v2"
52
+ },
53
+ {
54
+ "name": "@postman/tunnel-agent",
55
+ "version": "*",
56
+ "source": "shai-hulud-v2"
57
+ },
58
+ {
59
+ "name": "@zapier/secret-scrubber",
60
+ "version": "*",
61
+ "source": "shai-hulud-v2"
62
+ },
63
+ {
64
+ "name": "@vietmoney/react-big-calendar",
65
+ "version": "0.26.2",
66
+ "source": "shai-hulud-v3"
67
+ },
68
+ {
69
+ "name": "flatmap-stream",
70
+ "version": "0.1.1",
71
+ "source": "event-stream-2018"
72
+ },
73
+ {
74
+ "name": "event-stream",
75
+ "version": "3.3.6",
76
+ "source": "event-stream-2018"
77
+ },
78
+ {
79
+ "name": "eslint-scope",
80
+ "version": "3.7.2",
81
+ "source": "eslint-scope-2018"
82
+ },
83
+ {
84
+ "name": "eslint-config-prettier",
85
+ "version": "8.10.1",
86
+ "source": "eslint-prettier-2025"
87
+ },
88
+ {
89
+ "name": "eslint-config-prettier",
90
+ "version": "9.1.1",
91
+ "source": "eslint-prettier-2025"
92
+ },
93
+ {
94
+ "name": "eslint-plugin-prettier",
95
+ "version": "4.2.2",
96
+ "source": "eslint-prettier-2025"
97
+ },
98
+ {
99
+ "name": "synckit",
100
+ "version": "0.11.9",
101
+ "source": "eslint-prettier-2025"
102
+ },
103
+ {
104
+ "name": "@pkgr/core",
105
+ "version": "0.2.8",
106
+ "source": "eslint-prettier-2025"
107
+ },
108
+ {
109
+ "name": "napi-postinstall",
110
+ "version": "0.3.1",
111
+ "source": "eslint-prettier-2025"
112
+ },
113
+ {
114
+ "name": "got-fetch",
115
+ "version": "5.1.11",
116
+ "source": "eslint-prettier-2025"
117
+ },
118
+ {
119
+ "name": "is",
120
+ "version": "3.3.1",
121
+ "source": "is-package-2025"
122
+ },
123
+ {
124
+ "name": "is",
125
+ "version": "5.0.0",
126
+ "source": "is-package-2025"
127
+ },
128
+ {
129
+ "name": "crossenv",
130
+ "version": "*",
131
+ "source": "typosquat"
132
+ },
133
+ {
134
+ "name": "cross-env.js",
135
+ "version": "*",
136
+ "source": "typosquat"
137
+ },
138
+ {
139
+ "name": "mongose",
140
+ "version": "*",
141
+ "source": "typosquat"
142
+ },
143
+ {
144
+ "name": "mssql.js",
145
+ "version": "*",
146
+ "source": "typosquat"
147
+ },
148
+ {
149
+ "name": "mssql-node",
150
+ "version": "*",
151
+ "source": "typosquat"
152
+ },
153
+ {
154
+ "name": "babelcli",
155
+ "version": "*",
156
+ "source": "typosquat"
157
+ },
158
+ {
159
+ "name": "http-proxy.js",
160
+ "version": "*",
161
+ "source": "typosquat"
162
+ },
163
+ {
164
+ "name": "proxy.js",
165
+ "version": "*",
166
+ "source": "typosquat"
167
+ },
168
+ {
169
+ "name": "shadowsock",
170
+ "version": "*",
171
+ "source": "typosquat"
172
+ },
173
+ {
174
+ "name": "smb",
175
+ "version": "*",
176
+ "source": "typosquat"
177
+ },
178
+ {
179
+ "name": "nodesass",
180
+ "version": "*",
181
+ "source": "typosquat"
182
+ },
183
+ {
184
+ "name": "node-sass.js",
185
+ "version": "*",
186
+ "source": "typosquat"
187
+ },
188
+ {
189
+ "name": "node-ipc",
190
+ "version": "10.1.1",
191
+ "source": "protestware"
192
+ },
193
+ {
194
+ "name": "node-ipc",
195
+ "version": "10.1.2",
196
+ "source": "protestware"
197
+ },
198
+ {
199
+ "name": "node-ipc",
200
+ "version": "10.1.3",
201
+ "source": "protestware"
202
+ },
203
+ {
204
+ "name": "colors",
205
+ "version": "1.4.1",
206
+ "source": "protestware"
207
+ },
208
+ {
209
+ "name": "colors",
210
+ "version": "1.4.2",
211
+ "source": "protestware"
212
+ },
213
+ {
214
+ "name": "faker",
215
+ "version": "6.6.6",
216
+ "source": "protestware"
217
+ },
218
+ {
219
+ "name": "ua-parser-js",
220
+ "version": "0.7.29",
221
+ "source": "community",
222
+ "description": "Compromis octobre 2021 - crypto miner"
223
+ },
224
+ {
225
+ "name": "coa",
226
+ "version": "2.0.3",
227
+ "source": "community",
228
+ "description": "Compromis novembre 2021"
229
+ },
230
+ {
231
+ "name": "coa",
232
+ "version": "2.0.4",
233
+ "source": "community",
234
+ "description": "Compromis novembre 2021"
235
+ },
236
+ {
237
+ "name": "rc",
238
+ "version": "1.2.9",
239
+ "source": "community",
240
+ "description": "Compromis novembre 2021"
241
+ },
242
+ {
243
+ "name": "rc",
244
+ "version": "1.3.9",
245
+ "source": "community",
246
+ "description": "Compromis novembre 2021"
247
+ },
248
+ {
249
+ "name": "left-pad",
250
+ "version": "*",
251
+ "source": "community",
252
+ "description": "Incident 2016 - supply chain"
253
+ },
254
+ {
255
+ "name": "lodash-merge",
256
+ "version": "*",
257
+ "source": "typosquat",
258
+ "description": "Typosquat de lodash.merge"
259
+ },
260
+ {
261
+ "name": "loadash",
262
+ "version": "*",
263
+ "source": "typosquat",
264
+ "description": "Typosquat de lodash"
265
+ },
266
+ {
267
+ "name": "electorn",
268
+ "version": "*",
269
+ "source": "typosquat",
270
+ "description": "Typosquat de electron"
271
+ },
272
+ {
273
+ "name": "discord.js-selfbot-v11",
274
+ "version": "*",
275
+ "source": "community",
276
+ "description": "Token stealer Discord"
277
+ },
278
+ {
279
+ "name": "discord-selfbot-tools",
280
+ "version": "*",
281
+ "source": "community",
282
+ "description": "Token stealer Discord"
283
+ },
284
+ {
285
+ "name": "discordsystem",
286
+ "version": "*",
287
+ "source": "community",
288
+ "description": "Token stealer Discord"
289
+ },
290
+ {
291
+ "name": "discord-lofy",
292
+ "version": "*",
293
+ "source": "community",
294
+ "description": "Token stealer Discord"
295
+ },
296
+ {
297
+ "name": "prerequests",
298
+ "version": "*",
299
+ "source": "typosquat",
300
+ "description": "Typosquat de prerequests"
301
+ },
302
+ {
303
+ "name": "requstes",
304
+ "version": "*",
305
+ "source": "typosquat",
306
+ "description": "Typosquat de requests"
307
+ }
308
+ ],
309
+ "files": [
310
+ "setup_bun.js",
311
+ "bun_environment.js",
312
+ "bundle.js",
313
+ "node-gyp.dll",
314
+ "preinstall.js",
315
+ "postinstall.js",
316
+ "install.js",
317
+ "discord-webhook.js",
318
+ "token-grabber.js",
319
+ "stealer.js",
320
+ "inject.js"
321
+ ],
322
+ "hashes": [
323
+ "62ee164b9b306250c1172583f138c9614139264f889fa99614903c12755468d0",
324
+ "cbb9bc5a8496243e02f3cc080efbe3e4a1430ba0671f2e43a202bf45b05479cd",
325
+ "f099c5d9ec417d4445a0328ac0ada9cde79fc37410914103ae9c609cbc0ee068",
326
+ "a3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a",
327
+ "f1df4896244500671eb4aa63ebb48ea11cee196fafaa0e9874e17b24ac053c02",
328
+ "9d59fd0bcc14b671079824c704575f201b74276238dc07a9c12a93a84195648a",
329
+ "e0250076c1d2ac38777ea8f542431daf61fcbaab0ca9c196614b28065ef5b918",
330
+ "6c9628f72d2bb789fe8f097a611d61c8c53f2f21e47c6a5d8d3e0e0b8e5e8c8f",
331
+ "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
332
+ "4b2399646573bb737c4969563303d8ee2e9ddbd1b271f1ca9e35ea78062538db",
333
+ "46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09",
334
+ "b74caeaa75e077c99f7d44f46daaf9796a3be43ecf24f2a1fd381844669da777",
335
+ "dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c",
336
+ "8f3c4e2a1b5d6c7e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e",
337
+ "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
338
+ ],
339
+ "markers": [
340
+ "Sha1-Hulud",
341
+ "Shai-Hulud",
342
+ "The Second Coming",
343
+ "Goldox-T3chs",
344
+ "Only Happy Girl",
345
+ "peacenotwar",
346
+ "protestware",
347
+ "/dev/tcp",
348
+ "reverse shell",
349
+ "discord.com/api/webhooks",
350
+ "token grabber",
351
+ "crypto miner",
352
+ "xmrig"
353
+ ],
354
+ "updated": "2026-01-02T09:21:30.216Z"
355
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "muaddib-scanner",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Supply-chain threat detection & response for npm",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
- "muaddib": "./bin/muaddib.js"
7
+ "muaddib": "bin/muaddib.js"
8
8
  },
9
9
  "scripts": {
10
10
  "test": "node tests/run-tests.js",
@@ -26,7 +26,7 @@
26
26
  "license": "MIT",
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/DNSZLSK/muad-dib.git"
29
+ "url": "git+https://github.com/DNSZLSK/muad-dib.git"
30
30
  },
31
31
  "homepage": "https://github.com/DNSZLSK/muad-dib",
32
32
  "bugs": {
package/rapport.html ADDED
@@ -0,0 +1,159 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MUAD'DIB - Rapport de scan</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
10
+ background: #1a1a2e;
11
+ color: #eee;
12
+ margin: 0;
13
+ padding: 20px;
14
+ }
15
+ .container {
16
+ max-width: 1200px;
17
+ margin: 0 auto;
18
+ }
19
+ h1 {
20
+ color: #e94560;
21
+ border-bottom: 2px solid #e94560;
22
+ padding-bottom: 10px;
23
+ }
24
+ .summary {
25
+ display: flex;
26
+ gap: 20px;
27
+ margin: 20px 0;
28
+ }
29
+ .summary-card {
30
+ background: #16213e;
31
+ padding: 20px;
32
+ border-radius: 8px;
33
+ flex: 1;
34
+ }
35
+ .summary-card h3 {
36
+ margin: 0 0 10px 0;
37
+ color: #888;
38
+ font-size: 14px;
39
+ }
40
+ .summary-card .value {
41
+ font-size: 32px;
42
+ font-weight: bold;
43
+ }
44
+ .critical .value { color: #e94560; }
45
+ .high .value { color: #ff6b35; }
46
+ .medium .value { color: #f9c74f; }
47
+ .total .value { color: #4ecdc4; }
48
+ table {
49
+ width: 100%;
50
+ border-collapse: collapse;
51
+ margin-top: 20px;
52
+ }
53
+ th, td {
54
+ padding: 12px;
55
+ text-align: left;
56
+ border-bottom: 1px solid #333;
57
+ }
58
+ th {
59
+ background: #16213e;
60
+ color: #e94560;
61
+ }
62
+ tr.critical { background: rgba(233, 69, 96, 0.2); }
63
+ tr.high { background: rgba(255, 107, 53, 0.2); }
64
+ tr.medium { background: rgba(249, 199, 79, 0.1); }
65
+ .meta {
66
+ color: #666;
67
+ font-size: 12px;
68
+ margin-top: 40px;
69
+ }
70
+ .ok {
71
+ background: #16213e;
72
+ padding: 40px;
73
+ border-radius: 8px;
74
+ text-align: center;
75
+ color: #4ecdc4;
76
+ font-size: 24px;
77
+ }
78
+ </style>
79
+ </head>
80
+ <body>
81
+ <div class="container">
82
+ <h1>MUAD'DIB - Rapport de scan</h1>
83
+
84
+ <div class="summary">
85
+ <div class="summary-card total">
86
+ <h3>TOTAL</h3>
87
+ <div class="value">4</div>
88
+ </div>
89
+ <div class="summary-card critical">
90
+ <h3>CRITICAL</h3>
91
+ <div class="value">0</div>
92
+ </div>
93
+ <div class="summary-card high">
94
+ <h3>HIGH</h3>
95
+ <div class="value">3</div>
96
+ </div>
97
+ <div class="summary-card medium">
98
+ <h3>MEDIUM</h3>
99
+ <div class="value">1</div>
100
+ </div>
101
+ </div>
102
+
103
+
104
+ <table>
105
+ <thead>
106
+ <tr>
107
+ <th>Severite</th>
108
+ <th>Type</th>
109
+ <th>Message</th>
110
+ <th>Fichier</th>
111
+ <th>Recommandation</th>
112
+ </tr>
113
+ </thead>
114
+ <tbody>
115
+
116
+ <tr class="high">
117
+ <td>HIGH</td>
118
+ <td>sensitive_string</td>
119
+ <td>Reference a ".npmrc" detectee.</td>
120
+ <td>malicious.js</td>
121
+ <td>Reference a un chemin ou identifiant sensible. Verifier le contexte d'utilisation.</td>
122
+ </tr>
123
+
124
+ <tr class="high">
125
+ <td>HIGH</td>
126
+ <td>env_access</td>
127
+ <td>Acces a variable sensible process.env.GITHUB_TOKEN.</td>
128
+ <td>malicious.js</td>
129
+ <td>Acces a une variable d'environnement sensible. Verifier si les donnees sont exfiltrees.</td>
130
+ </tr>
131
+
132
+ <tr class="high">
133
+ <td>HIGH</td>
134
+ <td>sensitive_string</td>
135
+ <td>Reference a "api.github.com" detectee.</td>
136
+ <td>malicious.js</td>
137
+ <td>Reference a un chemin ou identifiant sensible. Verifier le contexte d'utilisation.</td>
138
+ </tr>
139
+
140
+ <tr class="medium">
141
+ <td>MEDIUM</td>
142
+ <td>dangerous_call_exec</td>
143
+ <td>Appel dangereux "exec" detecte.</td>
144
+ <td>malicious.js</td>
145
+ <td>Execution de commande systeme. Verifier les arguments passes.</td>
146
+ </tr>
147
+
148
+ </tbody>
149
+ </table>
150
+
151
+
152
+ <div class="meta">
153
+ <p>Cible: test/samples</p>
154
+ <p>Date: 2026-01-01T20:11:35.775Z</p>
155
+ <p>Genere par MUAD'DIB</p>
156
+ </div>
157
+ </div>
158
+ </body>
159
+ </html>
@@ -11,29 +11,32 @@ const EXCLUDED_FILES = [
11
11
  'src/response/playbooks.js'
12
12
  ];
13
13
 
14
- const EXCLUDED_DIRS = ['test', 'tests', 'node_modules', '.git', 'src', 'vscode-extension'];
14
+ const EXCLUDED_DIRS = [
15
+ 'test', 'tests', 'node_modules', '.git', 'src', 'vscode-extension',
16
+ 'scripts', 'bin', 'tools', 'build', 'dist', 'fixtures', 'examples',
17
+ '__tests__', '__mocks__', 'benchmark', 'benchmarks', 'docs', 'doc'
18
+ ];
15
19
 
16
20
  const DANGEROUS_CALLS = [
17
21
  'eval',
18
- 'Function',
19
- 'exec',
20
- 'execSync',
21
- 'spawn',
22
- 'spawnSync'
22
+ 'Function'
23
23
  ];
24
24
 
25
25
  const SENSITIVE_STRINGS = [
26
26
  '.npmrc',
27
27
  '.ssh',
28
- 'GITHUB_TOKEN',
29
- 'NPM_TOKEN',
30
- 'AWS_SECRET',
31
- 'api.github.com',
32
28
  'Shai-Hulud',
33
29
  'The Second Coming',
34
30
  'Goldox-T3chs'
35
31
  ];
36
32
 
33
+ // Strings qui ne sont PAS suspects
34
+ const SAFE_STRINGS = [
35
+ 'api.github.com',
36
+ 'registry.npmjs.org',
37
+ 'npmjs.com'
38
+ ];
39
+
37
40
  async function analyzeAST(targetPath) {
38
41
  const threats = [];
39
42
  const files = findJsFiles(targetPath);
@@ -45,6 +48,11 @@ async function analyzeAST(targetPath) {
45
48
  continue;
46
49
  }
47
50
 
51
+ // Ignorer les fichiers dans les dossiers de dev
52
+ if (isDevFile(relativePath)) {
53
+ continue;
54
+ }
55
+
48
56
  const content = fs.readFileSync(file, 'utf8');
49
57
  const fileThreats = analyzeFile(content, file, targetPath);
50
58
  threats.push(...fileThreats);
@@ -53,6 +61,27 @@ async function analyzeAST(targetPath) {
53
61
  return threats;
54
62
  }
55
63
 
64
+ function isDevFile(relativePath) {
65
+ const devPatterns = [
66
+ /^scripts\//,
67
+ /^bin\//,
68
+ /^tools\//,
69
+ /^build\//,
70
+ /^fixtures\//,
71
+ /^examples\//,
72
+ /^__tests__\//,
73
+ /^__mocks__\//,
74
+ /^benchmark/,
75
+ /^docs?\//,
76
+ /\.test\.js$/,
77
+ /\.spec\.js$/,
78
+ /test\.js$/,
79
+ /spec\.js$/
80
+ ];
81
+
82
+ return devPatterns.some(pattern => pattern.test(relativePath));
83
+ }
84
+
56
85
  function analyzeFile(content, filePath, basePath) {
57
86
  const threats = [];
58
87
  let ast;
@@ -64,7 +93,6 @@ function analyzeFile(content, filePath, basePath) {
64
93
  allowHashBang: true
65
94
  });
66
95
  } catch (e) {
67
- // Fichier non parseable, peut etre obfusque
68
96
  if (content.length > 1000 && content.split('\n').length < 10) {
69
97
  threats.push({
70
98
  type: 'possible_obfuscation',
@@ -76,7 +104,6 @@ function analyzeFile(content, filePath, basePath) {
76
104
  return threats;
77
105
  }
78
106
 
79
- // Analyse des appels de fonction
80
107
  walk.simple(ast, {
81
108
  CallExpression(node) {
82
109
  const callName = getCallName(node);
@@ -84,7 +111,7 @@ function analyzeFile(content, filePath, basePath) {
84
111
  if (DANGEROUS_CALLS.includes(callName)) {
85
112
  threats.push({
86
113
  type: 'dangerous_call_' + callName.toLowerCase(),
87
- severity: callName === 'eval' ? 'HIGH' : 'MEDIUM',
114
+ severity: 'HIGH',
88
115
  message: `Appel dangereux "${callName}" detecte.`,
89
116
  file: path.relative(basePath, filePath)
90
117
  });
@@ -104,6 +131,11 @@ function analyzeFile(content, filePath, basePath) {
104
131
 
105
132
  Literal(node) {
106
133
  if (typeof node.value === 'string') {
134
+ // Ignorer les strings safe
135
+ if (SAFE_STRINGS.some(s => node.value.includes(s))) {
136
+ return;
137
+ }
138
+
107
139
  for (const sensitive of SENSITIVE_STRINGS) {
108
140
  if (node.value.includes(sensitive)) {
109
141
  threats.push({
@@ -118,7 +150,6 @@ function analyzeFile(content, filePath, basePath) {
118
150
  },
119
151
 
120
152
  MemberExpression(node) {
121
- // Detecte process.env.XXX
122
153
  if (
123
154
  node.object?.object?.name === 'process' &&
124
155
  node.object?.property?.name === 'env'