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,24 @@
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: no-cryptojs
8
+ * Warns on usage of deprecated crypto-js library
9
+ * CWE-1104: Use of Unmaintained Third Party Components
10
+ *
11
+ * crypto-js is not maintained since 2022 and recommends using native crypto
12
+ * @see https://www.npmjs.com/package/crypto-js
13
+ */
14
+ import type { TSESLint } from '@interlace/eslint-devkit';
15
+ type MessageIds = 'deprecatedCryptojs' | 'useNativeCrypto' | 'useWebCrypto';
16
+ export interface Options {
17
+ /** Severity level. Default: 'warn' */
18
+ severity?: 'error' | 'warn';
19
+ }
20
+ type RuleOptions = [Options?];
21
+ export declare const noCryptojs: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
22
+ name: string;
23
+ };
24
+ export type { Options as NoCryptojsOptions };
@@ -0,0 +1,104 @@
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.noCryptojs = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ exports.noCryptojs = (0, eslint_devkit_1.createRule)({
11
+ name: 'no-cryptojs',
12
+ meta: {
13
+ type: 'suggestion',
14
+ docs: {
15
+ description: 'Disallow deprecated crypto-js library (use native crypto instead)',
16
+ },
17
+ hasSuggestions: true,
18
+ messages: {
19
+ deprecatedCryptojs: (0, eslint_devkit_1.formatLLMMessage)({
20
+ icon: eslint_devkit_1.MessageIcons.WARNING,
21
+ issueName: 'Deprecated crypto-js library',
22
+ cwe: 'CWE-1104',
23
+ description: 'crypto-js is no longer maintained (last update: 2022). Future vulnerabilities will not be patched.',
24
+ severity: 'MEDIUM',
25
+ fix: 'Migrate to native Node.js crypto module or Web Crypto API',
26
+ documentationLink: 'https://nodejs.org/api/crypto.html',
27
+ }),
28
+ useNativeCrypto: (0, eslint_devkit_1.formatLLMMessage)({
29
+ icon: eslint_devkit_1.MessageIcons.INFO,
30
+ issueName: 'Use Node.js crypto',
31
+ description: 'Node.js crypto module is maintained by the Node.js core team',
32
+ severity: 'LOW',
33
+ fix: 'import crypto from "node:crypto"',
34
+ documentationLink: 'https://nodejs.org/api/crypto.html',
35
+ }),
36
+ useWebCrypto: (0, eslint_devkit_1.formatLLMMessage)({
37
+ icon: eslint_devkit_1.MessageIcons.INFO,
38
+ issueName: 'Use Web Crypto API',
39
+ description: 'Web Crypto API works in browsers and Node.js',
40
+ severity: 'LOW',
41
+ fix: 'globalThis.crypto.subtle',
42
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API',
43
+ }),
44
+ },
45
+ schema: [
46
+ {
47
+ type: 'object',
48
+ properties: {
49
+ severity: {
50
+ type: 'string',
51
+ enum: ['error', 'warn'],
52
+ default: 'warn',
53
+ description: 'Severity level for the rule',
54
+ },
55
+ },
56
+ additionalProperties: false,
57
+ },
58
+ ],
59
+ },
60
+ defaultOptions: [
61
+ {
62
+ severity: 'warn',
63
+ },
64
+ ],
65
+ create(context) {
66
+ function reportDeprecatedLibrary(node) {
67
+ context.report({
68
+ node,
69
+ messageId: 'deprecatedCryptojs',
70
+ suggest: [
71
+ {
72
+ messageId: 'useNativeCrypto',
73
+ fix: () => null, // Complex migration
74
+ },
75
+ {
76
+ messageId: 'useWebCrypto',
77
+ fix: () => null, // Complex migration
78
+ },
79
+ ],
80
+ });
81
+ }
82
+ return {
83
+ // import CryptoJS from 'crypto-js'
84
+ ImportDeclaration(node) {
85
+ if (typeof node.source.value === 'string' &&
86
+ (node.source.value === 'crypto-js' || node.source.value.startsWith('crypto-js/'))) {
87
+ reportDeprecatedLibrary(node);
88
+ }
89
+ },
90
+ // const CryptoJS = require('crypto-js')
91
+ CallExpression(node) {
92
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
93
+ node.callee.name === 'require' &&
94
+ node.arguments.length === 1 &&
95
+ node.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
96
+ typeof node.arguments[0].value === 'string' &&
97
+ (node.arguments[0].value === 'crypto-js' || node.arguments[0].value.startsWith('crypto-js/'))) {
98
+ reportDeprecatedLibrary(node);
99
+ }
100
+ },
101
+ };
102
+ },
103
+ });
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-cryptojs/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
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: no-cryptojs-weak-random
8
+ * Detects crypto-js WordArray.random() which was insecure pre-3.2.1
9
+ * CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator
10
+ *
11
+ * CVE-2020-36732: crypto-js < 3.2.1 used Math.random() for crypto operations
12
+ * @see https://nvd.nist.gov/vuln/detail/CVE-2020-36732
13
+ */
14
+ import type { TSESLint } from '@interlace/eslint-devkit';
15
+ type MessageIds = 'weakRandom' | 'useNativeRandom';
16
+ export interface Options {
17
+ /** Allow in test files. Default: false */
18
+ allowInTests?: boolean;
19
+ }
20
+ type RuleOptions = [Options?];
21
+ export declare const noCryptojsWeakRandom: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
22
+ name: string;
23
+ };
24
+ export type { Options as NoCryptojsWeakRandomOptions };
@@ -0,0 +1,112 @@
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.noCryptojsWeakRandom = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ exports.noCryptojsWeakRandom = (0, eslint_devkit_1.createRule)({
11
+ name: 'no-cryptojs-weak-random',
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Disallow crypto-js WordArray.random() (CVE-2020-36732)',
16
+ },
17
+ hasSuggestions: true,
18
+ messages: {
19
+ weakRandom: (0, eslint_devkit_1.formatLLMMessage)({
20
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
21
+ issueName: 'Weak random in crypto-js',
22
+ cwe: 'CWE-338',
23
+ description: 'CryptoJS.lib.WordArray.random() was insecure in versions < 3.2.1 (CVE-2020-36732). Used Math.random() instead of CSPRNG.',
24
+ severity: 'CRITICAL',
25
+ fix: 'Use crypto.randomBytes() from Node.js or crypto.getRandomValues() in browsers',
26
+ documentationLink: 'https://nvd.nist.gov/vuln/detail/CVE-2020-36732',
27
+ }),
28
+ useNativeRandom: (0, eslint_devkit_1.formatLLMMessage)({
29
+ icon: eslint_devkit_1.MessageIcons.INFO,
30
+ issueName: 'Use native randomBytes',
31
+ description: 'Use cryptographically secure random from native crypto',
32
+ severity: 'LOW',
33
+ fix: 'crypto.randomBytes(32)',
34
+ documentationLink: 'https://nodejs.org/api/crypto.html#cryptorandombytessize-callback',
35
+ }),
36
+ },
37
+ schema: [
38
+ {
39
+ type: 'object',
40
+ properties: {
41
+ allowInTests: {
42
+ type: 'boolean',
43
+ default: false,
44
+ description: 'Allow in test files',
45
+ },
46
+ },
47
+ additionalProperties: false,
48
+ },
49
+ ],
50
+ },
51
+ defaultOptions: [
52
+ {
53
+ allowInTests: false,
54
+ },
55
+ ],
56
+ create(context, [options = {}]) {
57
+ const { allowInTests = false } = options;
58
+ const filename = context.filename;
59
+ const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
60
+ function checkCallExpression(node) {
61
+ if (isTestFile)
62
+ return;
63
+ // Check for CryptoJS.lib.WordArray.random()
64
+ // or WordArray.random()
65
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
66
+ const callee = node.callee;
67
+ // Check for .random() method
68
+ if (callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
69
+ callee.property.name === 'random') {
70
+ // Check if it's on WordArray
71
+ if (callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier && callee.object.name === 'WordArray') {
72
+ reportWeakRandom(node);
73
+ return;
74
+ }
75
+ // Check for CryptoJS.lib.WordArray.random()
76
+ if (callee.object.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
77
+ const innerObj = callee.object;
78
+ if (innerObj.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
79
+ innerObj.property.name === 'WordArray') {
80
+ reportWeakRandom(node);
81
+ return;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ // Check for CryptoJS.random or similar patterns
87
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
88
+ node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
89
+ node.callee.object.name === 'CryptoJS' &&
90
+ node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
91
+ node.callee.property.name === 'random') {
92
+ reportWeakRandom(node);
93
+ }
94
+ }
95
+ function reportWeakRandom(node) {
96
+ context.report({
97
+ node,
98
+ messageId: 'weakRandom',
99
+ suggest: [
100
+ {
101
+ messageId: 'useNativeRandom',
102
+ fix: () => null, // Complex refactoring
103
+ },
104
+ ],
105
+ });
106
+ }
107
+ return {
108
+ CallExpression: checkCallExpression,
109
+ };
110
+ },
111
+ });
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-cryptojs-weak-random/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
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
+ tempPaths?: string[];
8
+ ignoreFiles?: string[];
9
+ }
10
+ type RuleOptions = [Options?];
11
+ export declare const noDataInTempStorage: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
12
+ name: string;
13
+ };
14
+ export {};
@@ -0,0 +1,99 @@
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.noDataInTempStorage = void 0;
9
+ /**
10
+ * @fileoverview Prevent sensitive data in temp directories
11
+ */
12
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
13
+ const DEFAULT_TEMP_PATHS = ['/tmp', '/var/tmp', 'temp/', '/temp'];
14
+ exports.noDataInTempStorage = (0, eslint_devkit_1.createRule)({
15
+ name: 'no-data-in-temp-storage',
16
+ meta: {
17
+ type: 'problem',
18
+ docs: {
19
+ description: 'Prevent sensitive data in temp directories',
20
+ },
21
+ messages: {
22
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
23
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
24
+ issueName: 'Temp Storage Data',
25
+ cwe: 'CWE-312',
26
+ description: 'Sensitive data written to temp directory - not secure',
27
+ severity: 'HIGH',
28
+ fix: 'Use secure storage location or encrypt data before writing',
29
+ documentationLink: 'https://cwe.mitre.org/data/definitions/312.html',
30
+ })
31
+ },
32
+ schema: [
33
+ {
34
+ type: 'object',
35
+ properties: {
36
+ tempPaths: {
37
+ type: 'array',
38
+ items: { type: 'string' },
39
+ description: 'Custom list of temporary paths to flag'
40
+ },
41
+ ignoreFiles: {
42
+ type: 'array',
43
+ items: { type: 'string' },
44
+ description: 'List of files or patterns to ignore'
45
+ }
46
+ },
47
+ additionalProperties: false
48
+ }
49
+ ],
50
+ },
51
+ defaultOptions: [{}],
52
+ create(context) {
53
+ const options = context.options[0] || {};
54
+ const tempPaths = options.tempPaths || DEFAULT_TEMP_PATHS;
55
+ const ignoreFiles = options.ignoreFiles || [];
56
+ const filename = context.filename;
57
+ if (ignoreFiles.some(pattern => filename.includes(pattern))) {
58
+ return {};
59
+ }
60
+ function report(node) {
61
+ context.report({ node, messageId: 'violationDetected' });
62
+ }
63
+ return {
64
+ CallExpression(node) {
65
+ // Detect fs.writeFileSync or fs.writeFile with temp path
66
+ if (node.callee.type === 'MemberExpression' &&
67
+ node.callee.object.type === 'Identifier' &&
68
+ node.callee.object.name === 'fs' &&
69
+ node.callee.property.type === 'Identifier' &&
70
+ ['writeFileSync', 'writeFile'].includes(node.callee.property.name)) {
71
+ const pathArg = node.arguments[0];
72
+ if (pathArg && pathArg.type === 'Literal' && typeof pathArg.value === 'string') {
73
+ if (tempPaths.some(tp => pathArg.value.includes(tp))) {
74
+ report(pathArg);
75
+ }
76
+ }
77
+ }
78
+ },
79
+ Literal(node) {
80
+ // Detect temp path literals
81
+ if (typeof node.value === 'string') {
82
+ if (tempPaths.some(tp => node.value.includes(tp))) {
83
+ // Only flag if parent is assignment or variable declaration
84
+ const parent = node.parent;
85
+ if (parent?.type === 'VariableDeclarator' || parent?.type === 'AssignmentExpression') {
86
+ // Avoid double reporting if it's already handled by CallExpression
87
+ if (parent.type === 'VariableDeclarator' || parent.type === 'AssignmentExpression') {
88
+ // Check if it's the first argument of an fs call which is handled above
89
+ // Actually the Literal listener here catches it regardless of being in fs call or not if it's in a VariableDeclarator
90
+ }
91
+ report(node);
92
+ }
93
+ }
94
+ }
95
+ },
96
+ };
97
+ },
98
+ });
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-data-in-temp-storage/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: no-deprecated-cipher-method
8
+ * Detects use of deprecated crypto.createCipher/createDecipher methods
9
+ * CWE-327: These methods don't use IV, making encryption deterministic
10
+ *
11
+ * @see https://nodejs.org/api/crypto.html#cryptocreatecipheralgorithm-password-options
12
+ */
13
+ import type { TSESLint } from '@interlace/eslint-devkit';
14
+ type MessageIds = 'deprecatedCipherMethod' | 'useCipheriv';
15
+ export interface Options {
16
+ /** Allow deprecated methods in test files. Default: false */
17
+ allowInTests?: boolean;
18
+ }
19
+ type RuleOptions = [Options?];
20
+ export declare const noDeprecatedCipherMethod: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
21
+ name: string;
22
+ };
23
+ export type { Options as NoDeprecatedCipherMethodOptions };
@@ -0,0 +1,118 @@
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.noDeprecatedCipherMethod = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ const DEPRECATED_METHODS = new Set(['createCipher', 'createDecipher']);
11
+ exports.noDeprecatedCipherMethod = (0, eslint_devkit_1.createRule)({
12
+ name: 'no-deprecated-cipher-method',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Disallow deprecated crypto.createCipher/createDecipher methods (use createCipheriv/createDecipheriv instead)',
17
+ },
18
+ hasSuggestions: true,
19
+ messages: {
20
+ deprecatedCipherMethod: (0, eslint_devkit_1.formatLLMMessage)({
21
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
22
+ issueName: 'Deprecated cipher method',
23
+ cwe: 'CWE-327',
24
+ description: 'crypto.{{method}}() is deprecated. It derives key from password without salt and uses no IV, making encryption deterministic and vulnerable.',
25
+ severity: 'HIGH',
26
+ fix: 'Use crypto.{{replacement}}() with explicit key and random IV',
27
+ documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
28
+ }),
29
+ useCipheriv: (0, eslint_devkit_1.formatLLMMessage)({
30
+ icon: eslint_devkit_1.MessageIcons.INFO,
31
+ issueName: 'Use createCipheriv',
32
+ description: 'Use createCipheriv with explicit key derivation and random IV',
33
+ severity: 'LOW',
34
+ fix: 'const key = crypto.scryptSync(password, salt, 32);\nconst iv = crypto.randomBytes(16);\nconst cipher = crypto.createCipheriv(algorithm, key, iv);',
35
+ documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
36
+ }),
37
+ },
38
+ schema: [
39
+ {
40
+ type: 'object',
41
+ properties: {
42
+ allowInTests: {
43
+ type: 'boolean',
44
+ default: false,
45
+ description: 'Allow deprecated methods in test files',
46
+ },
47
+ },
48
+ additionalProperties: false,
49
+ },
50
+ ],
51
+ },
52
+ defaultOptions: [
53
+ {
54
+ allowInTests: false,
55
+ },
56
+ ],
57
+ create(context, [options = {}]) {
58
+ const { allowInTests = false } = options;
59
+ const filename = context.filename;
60
+ const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
61
+ function checkCallExpression(node) {
62
+ if (isTestFile)
63
+ return;
64
+ // Check for crypto.createCipher() or crypto.createDecipher()
65
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
66
+ node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
67
+ DEPRECATED_METHODS.has(node.callee.property.name)) {
68
+ // Capture narrowed type before callback (TypeScript loses narrowing in closures)
69
+ const callee = node.callee;
70
+ const propertyNode = callee.property;
71
+ const methodName = propertyNode.name;
72
+ const replacementName = methodName === 'createCipher' ? 'createCipheriv' : 'createDecipheriv';
73
+ context.report({
74
+ node: propertyNode,
75
+ messageId: 'deprecatedCipherMethod',
76
+ data: {
77
+ method: methodName,
78
+ replacement: replacementName,
79
+ },
80
+ suggest: [
81
+ {
82
+ messageId: 'useCipheriv',
83
+ fix: (fixer) => {
84
+ return fixer.replaceText(propertyNode, replacementName);
85
+ },
86
+ },
87
+ ],
88
+ });
89
+ }
90
+ // Check for standalone createCipher() / createDecipher()
91
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
92
+ DEPRECATED_METHODS.has(node.callee.name)) {
93
+ const methodName = node.callee.name;
94
+ const replacementName = methodName === 'createCipher' ? 'createCipheriv' : 'createDecipheriv';
95
+ context.report({
96
+ node: node.callee,
97
+ messageId: 'deprecatedCipherMethod',
98
+ data: {
99
+ method: methodName,
100
+ replacement: replacementName,
101
+ },
102
+ suggest: [
103
+ {
104
+ messageId: 'useCipheriv',
105
+ fix: (fixer) => {
106
+ return fixer.replaceText(node.callee, replacementName);
107
+ },
108
+ },
109
+ ],
110
+ });
111
+ }
112
+ }
113
+ return {
114
+ CallExpression: checkCallExpression,
115
+ };
116
+ },
117
+ });
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-deprecated-cipher-method/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 noDynamicDependencyLoading: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,55 @@
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.noDynamicDependencyLoading = void 0;
9
+ /**
10
+ * @fileoverview Prevent dynamic dependency injection
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/494.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
16
+ name: 'no-dynamic-dependency-loading',
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'Prevent runtime dependency injection with dynamic paths',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'violation Detected',
26
+ cwe: 'CWE-1104',
27
+ description: 'Dynamic import/require detected - use static imports for security',
28
+ severity: 'HIGH',
29
+ fix: 'Review and apply secure practices',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/1104.html',
31
+ })
32
+ },
33
+ schema: [],
34
+ },
35
+ defaultOptions: [],
36
+ create(context) {
37
+ return {
38
+ CallExpression(node) {
39
+ // Dynamic require
40
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
41
+ node.callee.name === 'require' &&
42
+ node.arguments[0]?.type !== eslint_devkit_1.AST_NODE_TYPES.Literal) {
43
+ context.report({ node, messageId: 'violationDetected' });
44
+ }
45
+ },
46
+ ImportExpression(node) {
47
+ // Dynamic import()
48
+ if (node.source.type !== 'Literal') {
49
+ context.report({ node, messageId: 'violationDetected' });
50
+ }
51
+ },
52
+ };
53
+ },
54
+ });
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-dynamic-dependency-loading/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAAsG;AAUzF,QAAA,0BAA0B,GAAG,IAAA,0BAAU,EAA0B;IAC5E,IAAI,EAAE,+BAA+B;IACrC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,yDAAyD;SACvE;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,oBAAoB;gBAC/B,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,mEAAmE;gBAChF,QAAQ,EAAE,MAAM;gBAChB,GAAG,EAAE,mCAAmC;gBACxC,iBAAiB,EAAE,kDAAkD;aACtE,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAA6B;gBAC1C,kBAAkB;gBAClB,IACE,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;oBAC9B,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,8BAAc,CAAC,OAAO,EAClD,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;YAED,gBAAgB,CAAC,IAA+B;gBAC9C,mBAAmB;gBACnB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBACnC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;SACH,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,21 @@
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: no-dynamic-require
8
+ * Forbid `require()` calls with expressions (eslint-plugin-import inspired)
9
+ */
10
+ import type { TSESLint } from '@interlace/eslint-devkit';
11
+ export interface Options {
12
+ /** Allow dynamic requires in specific contexts */
13
+ allowContexts?: ('test' | 'config' | 'build' | 'runtime')[];
14
+ /** Allow specific patterns of dynamic requires */
15
+ allowPatterns?: string[];
16
+ }
17
+ type RuleOptions = [Options?];
18
+ export declare const noDynamicRequire: TSESLint.RuleModule<"dynamicRequire", RuleOptions, unknown, TSESLint.RuleListener> & {
19
+ name: string;
20
+ };
21
+ export {};