eslint-plugin-node-security 4.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 (102) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +50 -0
  3. package/package.json +79 -0
  4. package/src/index.d.ts +10 -0
  5. package/src/index.js +118 -0
  6. package/src/index.js.map +1 -0
  7. package/src/rules/detect-child-process/index.d.ts +30 -0
  8. package/src/rules/detect-child-process/index.js +535 -0
  9. package/src/rules/detect-child-process/index.js.map +1 -0
  10. package/src/rules/detect-eval-with-expression/index.d.ts +28 -0
  11. package/src/rules/detect-eval-with-expression/index.js +398 -0
  12. package/src/rules/detect-eval-with-expression/index.js.map +1 -0
  13. package/src/rules/detect-non-literal-fs-filename/index.d.ts +26 -0
  14. package/src/rules/detect-non-literal-fs-filename/index.js +460 -0
  15. package/src/rules/detect-non-literal-fs-filename/index.js.map +1 -0
  16. package/src/rules/detect-suspicious-dependencies/index.d.ts +12 -0
  17. package/src/rules/detect-suspicious-dependencies/index.js +77 -0
  18. package/src/rules/detect-suspicious-dependencies/index.js.map +1 -0
  19. package/src/rules/lock-file/index.d.ts +13 -0
  20. package/src/rules/lock-file/index.js +94 -0
  21. package/src/rules/lock-file/index.js.map +1 -0
  22. package/src/rules/no-arbitrary-file-access/index.d.ts +12 -0
  23. package/src/rules/no-arbitrary-file-access/index.js +201 -0
  24. package/src/rules/no-arbitrary-file-access/index.js.map +1 -0
  25. package/src/rules/no-buffer-overread/index.d.ts +39 -0
  26. package/src/rules/no-buffer-overread/index.js +612 -0
  27. package/src/rules/no-buffer-overread/index.js.map +1 -0
  28. package/src/rules/no-cryptojs/index.d.ts +24 -0
  29. package/src/rules/no-cryptojs/index.js +104 -0
  30. package/src/rules/no-cryptojs/index.js.map +1 -0
  31. package/src/rules/no-cryptojs-weak-random/index.d.ts +24 -0
  32. package/src/rules/no-cryptojs-weak-random/index.js +112 -0
  33. package/src/rules/no-cryptojs-weak-random/index.js.map +1 -0
  34. package/src/rules/no-data-in-temp-storage/index.d.ts +14 -0
  35. package/src/rules/no-data-in-temp-storage/index.js +99 -0
  36. package/src/rules/no-data-in-temp-storage/index.js.map +1 -0
  37. package/src/rules/no-deprecated-cipher-method/index.d.ts +23 -0
  38. package/src/rules/no-deprecated-cipher-method/index.js +118 -0
  39. package/src/rules/no-deprecated-cipher-method/index.js.map +1 -0
  40. package/src/rules/no-dynamic-dependency-loading/index.d.ts +12 -0
  41. package/src/rules/no-dynamic-dependency-loading/index.js +55 -0
  42. package/src/rules/no-dynamic-dependency-loading/index.js.map +1 -0
  43. package/src/rules/no-dynamic-require/index.d.ts +21 -0
  44. package/src/rules/no-dynamic-require/index.js +122 -0
  45. package/src/rules/no-dynamic-require/index.js.map +1 -0
  46. package/src/rules/no-ecb-mode/index.d.ts +23 -0
  47. package/src/rules/no-ecb-mode/index.js +113 -0
  48. package/src/rules/no-ecb-mode/index.js.map +1 -0
  49. package/src/rules/no-insecure-key-derivation/index.d.ts +24 -0
  50. package/src/rules/no-insecure-key-derivation/index.js +116 -0
  51. package/src/rules/no-insecure-key-derivation/index.js.map +1 -0
  52. package/src/rules/no-insecure-rsa-padding/index.d.ts +24 -0
  53. package/src/rules/no-insecure-rsa-padding/index.js +110 -0
  54. package/src/rules/no-insecure-rsa-padding/index.js.map +1 -0
  55. package/src/rules/no-pii-in-logs/index.d.ts +12 -0
  56. package/src/rules/no-pii-in-logs/index.js +74 -0
  57. package/src/rules/no-pii-in-logs/index.js.map +1 -0
  58. package/src/rules/no-self-signed-certs/index.d.ts +23 -0
  59. package/src/rules/no-self-signed-certs/index.js +116 -0
  60. package/src/rules/no-self-signed-certs/index.js.map +1 -0
  61. package/src/rules/no-sha1-hash/index.d.ts +24 -0
  62. package/src/rules/no-sha1-hash/index.js +128 -0
  63. package/src/rules/no-sha1-hash/index.js.map +1 -0
  64. package/src/rules/no-static-iv/index.d.ts +23 -0
  65. package/src/rules/no-static-iv/index.js +147 -0
  66. package/src/rules/no-static-iv/index.js.map +1 -0
  67. package/src/rules/no-timing-unsafe-compare/index.d.ts +23 -0
  68. package/src/rules/no-timing-unsafe-compare/index.js +114 -0
  69. package/src/rules/no-timing-unsafe-compare/index.js.map +1 -0
  70. package/src/rules/no-toctou-vulnerability/index.d.ts +26 -0
  71. package/src/rules/no-toctou-vulnerability/index.js +214 -0
  72. package/src/rules/no-toctou-vulnerability/index.js.map +1 -0
  73. package/src/rules/no-unsafe-dynamic-require/index.d.ts +19 -0
  74. package/src/rules/no-unsafe-dynamic-require/index.js +112 -0
  75. package/src/rules/no-unsafe-dynamic-require/index.js.map +1 -0
  76. package/src/rules/no-weak-cipher-algorithm/index.d.ts +25 -0
  77. package/src/rules/no-weak-cipher-algorithm/index.js +190 -0
  78. package/src/rules/no-weak-cipher-algorithm/index.js.map +1 -0
  79. package/src/rules/no-weak-hash-algorithm/index.d.ts +25 -0
  80. package/src/rules/no-weak-hash-algorithm/index.js +218 -0
  81. package/src/rules/no-weak-hash-algorithm/index.js.map +1 -0
  82. package/src/rules/no-zip-slip/index.d.ts +35 -0
  83. package/src/rules/no-zip-slip/index.js +451 -0
  84. package/src/rules/no-zip-slip/index.js.map +1 -0
  85. package/src/rules/prefer-native-crypto/index.d.ts +23 -0
  86. package/src/rules/prefer-native-crypto/index.js +124 -0
  87. package/src/rules/prefer-native-crypto/index.js.map +1 -0
  88. package/src/rules/require-dependency-integrity/index.d.ts +12 -0
  89. package/src/rules/require-dependency-integrity/index.js +70 -0
  90. package/src/rules/require-dependency-integrity/index.js.map +1 -0
  91. package/src/rules/require-secure-credential-storage/index.d.ts +12 -0
  92. package/src/rules/require-secure-credential-storage/index.js +54 -0
  93. package/src/rules/require-secure-credential-storage/index.js.map +1 -0
  94. package/src/rules/require-secure-deletion/index.d.ts +12 -0
  95. package/src/rules/require-secure-deletion/index.js +46 -0
  96. package/src/rules/require-secure-deletion/index.js.map +1 -0
  97. package/src/rules/require-storage-encryption/index.d.ts +12 -0
  98. package/src/rules/require-storage-encryption/index.js +54 -0
  99. package/src/rules/require-storage-encryption/index.js.map +1 -0
  100. package/src/types/index.d.ts +24 -0
  101. package/src/types/index.js +8 -0
  102. package/src/types/index.js.map +1 -0
@@ -0,0 +1,451 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noZipSlip = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
+ exports.noZipSlip = (0, eslint_devkit_1.createRule)({
12
+ name: 'no-zip-slip',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Detects zip slip/archive extraction vulnerabilities',
17
+ },
18
+ fixable: 'code',
19
+ hasSuggestions: true,
20
+ messages: {
21
+ zipSlipVulnerability: (0, eslint_devkit_2.formatLLMMessage)({
22
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
23
+ issueName: 'Zip Slip Vulnerability',
24
+ cwe: 'CWE-22',
25
+ description: 'Archive extraction vulnerable to path traversal',
26
+ severity: '{{severity}}',
27
+ fix: '{{safeAlternative}}',
28
+ documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
29
+ }),
30
+ unsafeArchiveExtraction: (0, eslint_devkit_2.formatLLMMessage)({
31
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
32
+ issueName: 'Unsafe Archive Extraction',
33
+ cwe: 'CWE-22',
34
+ description: 'Archive extraction without path validation',
35
+ severity: 'HIGH',
36
+ fix: 'Use safe extraction libraries or validate all paths',
37
+ documentationLink: 'https://snyk.io/research/zip-slip-vulnerability',
38
+ }),
39
+ pathTraversalInArchive: (0, eslint_devkit_2.formatLLMMessage)({
40
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
41
+ issueName: 'Path Traversal in Archive',
42
+ cwe: 'CWE-22',
43
+ description: 'Archive contains path traversal sequences',
44
+ severity: 'CRITICAL',
45
+ fix: 'Reject archives with path traversal or sanitize paths',
46
+ documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
47
+ }),
48
+ unvalidatedArchivePath: (0, eslint_devkit_2.formatLLMMessage)({
49
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
50
+ issueName: 'Unvalidated Archive Path',
51
+ cwe: 'CWE-22',
52
+ description: 'Archive entry path used without validation',
53
+ severity: 'HIGH',
54
+ fix: 'Validate paths before extraction',
55
+ documentationLink: 'https://snyk.io/research/zip-slip-vulnerability',
56
+ }),
57
+ dangerousArchiveDestination: (0, eslint_devkit_2.formatLLMMessage)({
58
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
59
+ issueName: 'Dangerous Archive Destination',
60
+ cwe: 'CWE-22',
61
+ description: 'Archive extracted to sensitive location',
62
+ severity: 'MEDIUM',
63
+ fix: 'Extract to safe temporary directory',
64
+ documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
65
+ }),
66
+ useSafeArchiveExtraction: (0, eslint_devkit_2.formatLLMMessage)({
67
+ icon: eslint_devkit_2.MessageIcons.INFO,
68
+ issueName: 'Use Safe Archive Extraction',
69
+ description: 'Use libraries with built-in path validation',
70
+ severity: 'LOW',
71
+ fix: 'Use yauzl, safe-archive-extract, or similar safe libraries',
72
+ documentationLink: 'https://www.npmjs.com/package/yauzl',
73
+ }),
74
+ validateArchivePaths: (0, eslint_devkit_2.formatLLMMessage)({
75
+ icon: eslint_devkit_2.MessageIcons.INFO,
76
+ issueName: 'Validate Archive Paths',
77
+ description: 'Validate all archive entry paths',
78
+ severity: 'LOW',
79
+ fix: 'Check paths don\'t contain ../ and are within destination directory',
80
+ documentationLink: 'https://snyk.io/research/zip-slip-vulnerability',
81
+ }),
82
+ sanitizeArchiveNames: (0, eslint_devkit_2.formatLLMMessage)({
83
+ icon: eslint_devkit_2.MessageIcons.INFO,
84
+ issueName: 'Sanitize Archive Names',
85
+ description: 'Sanitize archive entry names',
86
+ severity: 'LOW',
87
+ fix: 'Use path.basename() or custom sanitization',
88
+ documentationLink: 'https://nodejs.org/api/path.html#pathbasenamepath-ext',
89
+ }),
90
+ strategyPathValidation: (0, eslint_devkit_2.formatLLMMessage)({
91
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
92
+ issueName: 'Path Validation Strategy',
93
+ description: 'Validate paths before any file operations',
94
+ severity: 'LOW',
95
+ fix: 'Check path.startsWith(destination) and no ../ sequences',
96
+ documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
97
+ }),
98
+ strategySafeLibraries: (0, eslint_devkit_2.formatLLMMessage)({
99
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
100
+ issueName: 'Safe Libraries Strategy',
101
+ description: 'Use archive libraries with built-in safety',
102
+ severity: 'LOW',
103
+ fix: 'Use yauzl, adm-zip with validation, or safe-archive-extract',
104
+ documentationLink: 'https://www.npmjs.com/package/safe-archive-extract',
105
+ }),
106
+ strategySandboxing: (0, eslint_devkit_2.formatLLMMessage)({
107
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
108
+ issueName: 'Sandboxing Strategy',
109
+ description: 'Extract archives in sandboxed environment',
110
+ severity: 'LOW',
111
+ fix: 'Use temporary directories and restrict permissions',
112
+ documentationLink: 'https://nodejs.org/api/fs.html#fsopentempdirprefix-options-callback',
113
+ })
114
+ },
115
+ schema: [
116
+ {
117
+ type: 'object',
118
+ properties: {
119
+ archiveFunctions: {
120
+ type: 'array',
121
+ items: { type: 'string' },
122
+ default: ['extract', 'extractAll', 'extractAllTo', 'unzip', 'untar', 'extractArchive'],
123
+ },
124
+ pathValidationFunctions: {
125
+ type: 'array',
126
+ items: { type: 'string' },
127
+ default: ['validatePath', 'sanitizePath', 'checkPath', 'safePath'],
128
+ },
129
+ safeLibraries: {
130
+ type: 'array',
131
+ items: { type: 'string' },
132
+ default: ['yauzl', 'safe-archive-extract', 'tar-stream', 'unzipper'],
133
+ },
134
+ },
135
+ additionalProperties: false,
136
+ },
137
+ ],
138
+ },
139
+ defaultOptions: [
140
+ {
141
+ archiveFunctions: ['extract', 'extractAll', 'extractAllTo', 'unzip', 'untar', 'extractArchive'],
142
+ pathValidationFunctions: ['validatePath', 'sanitizePath', 'checkPath', 'safePath'],
143
+ safeLibraries: ['yauzl', 'safe-archive-extract', 'tar-stream', 'unzipper'],
144
+ },
145
+ ],
146
+ create(context) {
147
+ const options = context.options[0] || {};
148
+ const { archiveFunctions = ['extract', 'extractAll', 'extractAllTo', 'unzip', 'untar', 'extractArchive'], pathValidationFunctions = ['validatePath', 'sanitizePath', 'checkPath', 'safePath'], safeLibraries = ['yauzl', 'safe-archive-extract', 'tar-stream', 'unzipper'], } = options;
149
+ const filename = context.filename || context.getFilename();
150
+ // Safety checks are implemented directly in the handlers
151
+ /**
152
+ * Check if this is an archive extraction operation
153
+ */
154
+ const isArchiveExtraction = (node) => {
155
+ const callee = node.callee;
156
+ // Check for archive method calls (e.g., zip.extractAllTo)
157
+ if (callee.type === 'MemberExpression' &&
158
+ callee.property.type === 'Identifier' &&
159
+ archiveFunctions.includes(callee.property.name)) {
160
+ return true;
161
+ }
162
+ // Check for standalone archive functions (e.g., extractArchive)
163
+ if (callee.type === 'Identifier' &&
164
+ archiveFunctions.includes(callee.name)) {
165
+ return true;
166
+ }
167
+ return false;
168
+ };
169
+ /**
170
+ * Check if path contains dangerous traversal sequences
171
+ */
172
+ const containsPathTraversal = (pathText) => {
173
+ // Check for ../ sequences
174
+ return /\.\.\//.test(pathText) ||
175
+ /\.\.\\/.test(pathText) || // Windows paths
176
+ /^\.\./.test(pathText) || // Leading ..
177
+ /\/\.\./.test(pathText); // Embedded /..
178
+ };
179
+ /**
180
+ * Check if path has been validated
181
+ */
182
+ const isPathValidated = (pathNode) => {
183
+ let current = pathNode;
184
+ while (current) {
185
+ if (current.type === 'CallExpression' &&
186
+ current.callee.type === 'Identifier' &&
187
+ pathValidationFunctions.includes(current.callee.name)) {
188
+ return true;
189
+ }
190
+ current = current.parent;
191
+ }
192
+ return false;
193
+ };
194
+ /**
195
+ * Check if this uses a safe library
196
+ */
197
+ const isSafeLibrary = (node) => {
198
+ const callee = node.callee;
199
+ if (callee.type === 'MemberExpression' &&
200
+ callee.object.type === 'Identifier' &&
201
+ safeLibraries.includes(callee.object.name)) {
202
+ return true;
203
+ }
204
+ return false;
205
+ };
206
+ /**
207
+ * Check if destination is dangerous
208
+ */
209
+ const isDangerousDestination = (destText) => {
210
+ return destText.includes('/tmp') ||
211
+ destText.includes('/var') ||
212
+ destText.includes('/usr') ||
213
+ destText.includes('/etc') ||
214
+ destText.includes('/root') ||
215
+ destText.includes('/home') ||
216
+ destText.includes('C:\\Windows') ||
217
+ destText.includes('C:\\Program Files') ||
218
+ destText.includes('C:\\Users');
219
+ };
220
+ return {
221
+ // Check archive extraction calls
222
+ CallExpression(node) {
223
+ if (isArchiveExtraction(node) && !isSafeLibrary(node)) {
224
+ // Check for @safe annotations in the source
225
+ const sourceCode = context.sourceCode;
226
+ let hasSafeAnnotation = false;
227
+ // Look for @safe comments in the source code
228
+ const allComments = sourceCode.getAllComments();
229
+ for (const comment of allComments) {
230
+ if (comment.type === 'Block' && comment.value.includes('@safe')) {
231
+ hasSafeAnnotation = true;
232
+ break;
233
+ }
234
+ }
235
+ if (hasSafeAnnotation) {
236
+ return; // Skip reporting if marked as safe
237
+ }
238
+ // Check if destination is dangerous
239
+ const args = node.arguments;
240
+ let destArg;
241
+ // Determine which argument is the destination based on the function
242
+ if (node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier') {
243
+ const methodName = node.callee.property.name;
244
+ if (['extractAllTo', 'unzip'].includes(methodName)) {
245
+ // Destination is the first argument
246
+ destArg = args[0];
247
+ }
248
+ else if (archiveFunctions.includes(methodName)) {
249
+ // For other archive functions, destination is typically the second argument
250
+ destArg = args.length >= 2 ? args[1] : undefined;
251
+ }
252
+ }
253
+ else if (node.callee.type === 'Identifier' && archiveFunctions.includes(node.callee.name)) {
254
+ // For standalone functions like extractArchive(file, dest)
255
+ destArg = args.length >= 2 ? args[1] : undefined;
256
+ }
257
+ const destText = destArg && destArg.type === 'Literal' && typeof destArg.value === 'string' ? destArg.value : '';
258
+ const isDestDangerous = isDangerousDestination(destText);
259
+ const isMethodCall = node.callee.type === 'MemberExpression';
260
+ if (isMethodCall) {
261
+ // Method calls report unsafeArchiveExtraction unless destination is a safe relative path
262
+ const isSafeRelativePath = destText.startsWith('./') || destText.startsWith('../');
263
+ if (!isSafeRelativePath) {
264
+ context.report({
265
+ node,
266
+ messageId: 'unsafeArchiveExtraction',
267
+ data: {
268
+ filePath: filename,
269
+ line: String(node.loc?.start.line ?? 0),
270
+ },
271
+ suggest: [
272
+ {
273
+ messageId: 'useSafeArchiveExtraction',
274
+ fix: () => null,
275
+ },
276
+ ],
277
+ });
278
+ }
279
+ // For safe relative paths, don't report any error
280
+ // Additionally report dangerous destination for dangerous destinations
281
+ if (isDestDangerous) {
282
+ context.report({
283
+ node: destArg || node,
284
+ messageId: 'dangerousArchiveDestination',
285
+ data: {
286
+ filePath: filename,
287
+ line: String(node.loc?.start.line ?? 0),
288
+ },
289
+ });
290
+ }
291
+ }
292
+ else {
293
+ // Standalone calls: report dangerousArchiveDestination for dangerous destinations, unsafeArchiveExtraction otherwise
294
+ if (isDestDangerous) {
295
+ context.report({
296
+ node,
297
+ messageId: 'dangerousArchiveDestination',
298
+ data: {
299
+ filePath: filename,
300
+ line: String(node.loc?.start.line ?? 0),
301
+ },
302
+ });
303
+ }
304
+ else {
305
+ context.report({
306
+ node,
307
+ messageId: 'unsafeArchiveExtraction',
308
+ data: {
309
+ filePath: filename,
310
+ line: String(node.loc?.start.line ?? 0),
311
+ },
312
+ suggest: [
313
+ {
314
+ messageId: 'useSafeArchiveExtraction',
315
+ fix: () => null
316
+ },
317
+ ],
318
+ });
319
+ }
320
+ }
321
+ }
322
+ // Check for path.join or similar operations with archive entry names
323
+ const callee = node.callee;
324
+ if (callee.type === 'MemberExpression' &&
325
+ callee.property.type === 'Identifier' &&
326
+ ['join', 'resolve', 'relative', 'normalize'].includes(callee.property.name)) {
327
+ // Check arguments for potential archive entry usage
328
+ const args = node.arguments;
329
+ for (const arg of args) {
330
+ if (arg.type === 'MemberExpression' &&
331
+ arg.property.type === 'Identifier' &&
332
+ ['name', 'path', 'fileName', 'entryName', 'relativePath', 'filename', 'pathname'].includes(arg.property.name)) {
333
+ // This looks like path.join(dest, entry.name) - check if validated
334
+ if (!isPathValidated(arg)) {
335
+ context.report({
336
+ node: arg,
337
+ messageId: 'unvalidatedArchivePath',
338
+ data: {
339
+ filePath: filename,
340
+ line: String(node.loc?.start.line ?? 0),
341
+ },
342
+ });
343
+ }
344
+ }
345
+ }
346
+ }
347
+ },
348
+ // Check string literals for dangerous paths
349
+ Literal(node) {
350
+ if (typeof node.value !== 'string') {
351
+ return;
352
+ }
353
+ const text = node.value;
354
+ // Check for path traversal in strings that look like file paths
355
+ if ((text.includes('/') || text.includes('\\')) && containsPathTraversal(text)) {
356
+ // Check if this is in an archive-related context
357
+ let current = node;
358
+ let isArchiveContext = false;
359
+ while (current && !isArchiveContext) {
360
+ if (current.type === 'CallExpression' && isArchiveExtraction(current)) {
361
+ isArchiveContext = true;
362
+ break;
363
+ }
364
+ if (current.type === 'VariableDeclarator' &&
365
+ current.id.type === 'Identifier' &&
366
+ (current.id.name.includes('archive') ||
367
+ current.id.name.includes('zip') ||
368
+ current.id.name.includes('tar') ||
369
+ current.id.name.includes('path') ||
370
+ current.id.name.includes('file') ||
371
+ current.id.name.includes('entry'))) {
372
+ isArchiveContext = true;
373
+ break;
374
+ }
375
+ current = current.parent;
376
+ }
377
+ // Also check if the variable name suggests archive usage
378
+ const parent = node.parent;
379
+ if (parent && parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') {
380
+ const varName = parent.id.name.toLowerCase();
381
+ if (varName.includes('archive') || varName.includes('zip') || varName.includes('tar') ||
382
+ varName.includes('path') || varName.includes('file') || varName.includes('extract') ||
383
+ varName.includes('entry')) {
384
+ isArchiveContext = true;
385
+ }
386
+ }
387
+ if (isArchiveContext) {
388
+ context.report({
389
+ node,
390
+ messageId: 'pathTraversalInArchive',
391
+ data: {
392
+ filePath: filename,
393
+ line: String(node.loc?.start.line ?? 0),
394
+ },
395
+ });
396
+ }
397
+ }
398
+ // Dangerous destinations are handled by the CallExpression handler to avoid duplicates
399
+ // Only check for dangerous destinations not related to archive extraction
400
+ if (isDangerousDestination(text) && !containsPathTraversal(text)) {
401
+ // Check if this is used as an extraction destination
402
+ let current = node;
403
+ let isExtractionDest = false;
404
+ while (current && !isExtractionDest) {
405
+ if (current.type === 'CallExpression' && isArchiveExtraction(current)) {
406
+ // Check if this node is a destination argument
407
+ const args = current.arguments;
408
+ const callee = current.callee;
409
+ const isMethodCall = callee.type === 'MemberExpression';
410
+ if ((isMethodCall && args.length >= 1 && args[0] === node) ||
411
+ (!isMethodCall && args.length >= 2 && args[1] === node)) {
412
+ isExtractionDest = true;
413
+ break;
414
+ }
415
+ }
416
+ current = current.parent;
417
+ }
418
+ // Only report if not already handled by CallExpression handler
419
+ if (!isExtractionDest) {
420
+ context.report({
421
+ node,
422
+ messageId: 'dangerousArchiveDestination',
423
+ data: {
424
+ filePath: filename,
425
+ line: String(node.loc?.start.line ?? 0),
426
+ },
427
+ });
428
+ }
429
+ }
430
+ },
431
+ // Check variable assignments
432
+ VariableDeclarator(node) {
433
+ if (!node.init || node.id.type !== 'Identifier') {
434
+ return;
435
+ }
436
+ const varName = node.id.name.toLowerCase();
437
+ // Check if this variable holds archive-related data
438
+ if (varName.includes('entry') || varName.includes('file') || varName.includes('path')) {
439
+ if (node.init.type === 'MemberExpression' &&
440
+ node.init.property.type === 'Identifier' &&
441
+ ['name', 'path'].includes(node.init.property.name)) {
442
+ // This looks like: const entryName = entry.name;
443
+ // Check if this variable is used unsafely later
444
+ // This is a simplified check - in practice we'd need more sophisticated analysis
445
+ }
446
+ }
447
+ }
448
+ };
449
+ },
450
+ });
451
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-zip-slip/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ /**
7
+ * ESLint Rule: prefer-native-crypto
8
+ * Suggests using native crypto over third-party libraries
9
+ * CWE-1104: Use of Unmaintained Third Party Components
10
+ *
11
+ * Native crypto is maintained by Node.js/browser vendors and is always up-to-date
12
+ */
13
+ import type { TSESLint } from '@interlace/eslint-devkit';
14
+ type MessageIds = 'preferNative' | 'useNodeCrypto' | 'useWebCrypto';
15
+ export interface Options {
16
+ /** Severity level. Default: 'warn' */
17
+ severity?: 'error' | 'warn';
18
+ }
19
+ type RuleOptions = [Options?];
20
+ export declare const preferNativeCrypto: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
21
+ name: string;
22
+ };
23
+ export type { Options as PreferNativeCryptoOptions };
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.preferNativeCrypto = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ // Third-party crypto libraries that should be replaced with native
11
+ const THIRD_PARTY_CRYPTO_LIBS = new Set([
12
+ 'crypto-js',
13
+ 'cryptojs',
14
+ 'sjcl', // Stanford JavaScript Crypto Library
15
+ 'forge', // node-forge
16
+ 'node-forge',
17
+ 'jsencrypt',
18
+ 'bcryptjs', // pure JS bcrypt (prefer native bcrypt)
19
+ 'js-sha256',
20
+ 'js-sha512',
21
+ 'js-sha3',
22
+ 'js-md5',
23
+ 'blueimp-md5',
24
+ 'aes-js',
25
+ ]);
26
+ exports.preferNativeCrypto = (0, eslint_devkit_1.createRule)({
27
+ name: 'prefer-native-crypto',
28
+ meta: {
29
+ type: 'suggestion',
30
+ docs: {
31
+ description: 'Prefer native crypto over third-party libraries',
32
+ },
33
+ hasSuggestions: true,
34
+ messages: {
35
+ preferNative: (0, eslint_devkit_1.formatLLMMessage)({
36
+ icon: eslint_devkit_1.MessageIcons.WARNING,
37
+ issueName: 'Third-party crypto library',
38
+ cwe: 'CWE-1104',
39
+ description: '{{library}} is a third-party crypto library. Native crypto (Node.js crypto or Web Crypto API) is faster, more secure, and always maintained.',
40
+ severity: 'MEDIUM',
41
+ fix: 'Migrate to native crypto module',
42
+ documentationLink: 'https://nodejs.org/api/crypto.html',
43
+ }),
44
+ useNodeCrypto: (0, eslint_devkit_1.formatLLMMessage)({
45
+ icon: eslint_devkit_1.MessageIcons.INFO,
46
+ issueName: 'Use Node.js crypto',
47
+ description: 'Node.js crypto module is built-in and maintained',
48
+ severity: 'LOW',
49
+ fix: 'import crypto from "node:crypto"',
50
+ documentationLink: 'https://nodejs.org/api/crypto.html',
51
+ }),
52
+ useWebCrypto: (0, eslint_devkit_1.formatLLMMessage)({
53
+ icon: eslint_devkit_1.MessageIcons.INFO,
54
+ issueName: 'Use Web Crypto API',
55
+ description: 'Web Crypto API is built into browsers and Node.js 15+',
56
+ severity: 'LOW',
57
+ fix: 'globalThis.crypto.subtle',
58
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API',
59
+ }),
60
+ },
61
+ schema: [
62
+ {
63
+ type: 'object',
64
+ properties: {
65
+ severity: {
66
+ type: 'string',
67
+ enum: ['error', 'warn'],
68
+ default: 'warn',
69
+ description: 'Severity level',
70
+ },
71
+ },
72
+ additionalProperties: false,
73
+ },
74
+ ],
75
+ },
76
+ defaultOptions: [
77
+ {
78
+ severity: 'warn',
79
+ },
80
+ ],
81
+ create(context) {
82
+ function reportThirdPartyLib(node, library) {
83
+ /* c8 ignore next 15 -- suggestions with fix: () => null cannot be tested with RuleTester */
84
+ context.report({
85
+ node,
86
+ messageId: 'preferNative',
87
+ data: { library },
88
+ suggest: [
89
+ {
90
+ messageId: 'useNodeCrypto',
91
+ fix: () => null,
92
+ },
93
+ {
94
+ messageId: 'useWebCrypto',
95
+ fix: () => null,
96
+ },
97
+ ],
98
+ });
99
+ }
100
+ return {
101
+ ImportDeclaration(node) {
102
+ if (typeof node.source.value === 'string') {
103
+ const lib = node.source.value.split('/')[0]; // Get base package name
104
+ if (THIRD_PARTY_CRYPTO_LIBS.has(lib)) {
105
+ reportThirdPartyLib(node, lib);
106
+ }
107
+ }
108
+ },
109
+ CallExpression(node) {
110
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
111
+ node.callee.name === 'require' &&
112
+ node.arguments.length === 1 &&
113
+ node.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
114
+ typeof node.arguments[0].value === 'string') {
115
+ const lib = node.arguments[0].value.split('/')[0];
116
+ if (THIRD_PARTY_CRYPTO_LIBS.has(lib)) {
117
+ reportThirdPartyLib(node, lib);
118
+ }
119
+ }
120
+ },
121
+ };
122
+ },
123
+ });
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/prefer-native-crypto/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const requireDependencyIntegrity: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};