eslint-plugin-node-security 4.6.0 → 4.7.1

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 (120) hide show
  1. package/README.md +1 -0
  2. package/package.json +5 -18
  3. package/src/index.d.ts +17 -10
  4. package/src/index.js +5 -36
  5. package/src/oxlint.d.ts +17 -20
  6. package/src/oxlint.js +0 -19
  7. package/src/rules/detect-child-process/index.js +0 -107
  8. package/src/rules/detect-eval-with-expression/index.js +2 -48
  9. package/src/rules/detect-non-literal-fs-filename/index.js +0 -82
  10. package/src/rules/detect-suspicious-dependencies/index.js +0 -12
  11. package/src/rules/lock-file/index.js +0 -18
  12. package/src/rules/no-arbitrary-file-access/index.js +0 -52
  13. package/src/rules/no-buffer-overread/index.js +3 -96
  14. package/src/rules/no-cryptojs/index.js +2 -10
  15. package/src/rules/no-cryptojs-weak-random/index.js +1 -13
  16. package/src/rules/no-data-in-temp-storage/index.js +0 -12
  17. package/src/rules/no-deprecated-buffer/index.js +0 -15
  18. package/src/rules/no-deprecated-cipher-method/index.js +0 -9
  19. package/src/rules/no-dynamic-algorithm-selection/index.js +0 -13
  20. package/src/rules/no-dynamic-command-string/index.js +201 -0
  21. package/src/rules/no-dynamic-dependency-loading/index.js +0 -13
  22. package/src/rules/no-dynamic-require/index.js +0 -10
  23. package/src/rules/no-ecb-mode/index.js +0 -7
  24. package/src/rules/no-insecure-key-derivation/index.js +0 -10
  25. package/src/rules/no-insecure-rsa-padding/index.js +0 -9
  26. package/src/rules/no-math-random-crypto/index.js +1 -17
  27. package/src/rules/no-self-signed-certs/index.js +1 -9
  28. package/src/rules/no-sha1-hash/index.js +0 -9
  29. package/src/rules/no-shell-injection/index.js +0 -20
  30. package/src/rules/no-ssrf/index.js +4 -80
  31. package/src/rules/no-static-iv/index.js +2 -21
  32. package/src/rules/no-timing-unsafe-compare/index.js +1 -11
  33. package/src/rules/no-toctou-vulnerability/index.js +0 -22
  34. package/src/rules/no-unsafe-buffer-alloc/index.js +0 -13
  35. package/src/rules/no-unsafe-dynamic-require/index.js +0 -22
  36. package/src/rules/no-weak-cipher-algorithm/index.js +0 -19
  37. package/src/rules/no-weak-hash-algorithm/index.js +0 -22
  38. package/src/rules/no-zip-slip/index.js +3 -81
  39. package/src/rules/prefer-native-crypto/index.js +4 -11
  40. package/src/rules/require-dependency-integrity/index.js +0 -11
  41. package/src/rules/require-secure-credential-storage/index.js +0 -12
  42. package/src/rules/require-secure-deletion/index.js +0 -29
  43. package/src/rules/require-storage-encryption/index.js +0 -12
  44. package/src/types/index.js +0 -6
  45. package/CHANGELOG.md +0 -413
  46. package/src/index.js.map +0 -1
  47. package/src/oxlint.js.map +0 -1
  48. package/src/rules/detect-child-process/index.d.ts +0 -52
  49. package/src/rules/detect-child-process/index.js.map +0 -1
  50. package/src/rules/detect-eval-with-expression/index.d.ts +0 -46
  51. package/src/rules/detect-eval-with-expression/index.js.map +0 -1
  52. package/src/rules/detect-non-literal-fs-filename/index.d.ts +0 -52
  53. package/src/rules/detect-non-literal-fs-filename/index.js.map +0 -1
  54. package/src/rules/detect-suspicious-dependencies/index.d.ts +0 -12
  55. package/src/rules/detect-suspicious-dependencies/index.js.map +0 -1
  56. package/src/rules/lock-file/index.d.ts +0 -13
  57. package/src/rules/lock-file/index.js.map +0 -1
  58. package/src/rules/no-arbitrary-file-access/index.d.ts +0 -12
  59. package/src/rules/no-arbitrary-file-access/index.js.map +0 -1
  60. package/src/rules/no-buffer-overread/index.d.ts +0 -39
  61. package/src/rules/no-buffer-overread/index.js.map +0 -1
  62. package/src/rules/no-cryptojs/index.d.ts +0 -24
  63. package/src/rules/no-cryptojs/index.js.map +0 -1
  64. package/src/rules/no-cryptojs-weak-random/index.d.ts +0 -24
  65. package/src/rules/no-cryptojs-weak-random/index.js.map +0 -1
  66. package/src/rules/no-data-in-temp-storage/index.d.ts +0 -14
  67. package/src/rules/no-data-in-temp-storage/index.js.map +0 -1
  68. package/src/rules/no-deprecated-buffer/index.d.ts +0 -23
  69. package/src/rules/no-deprecated-buffer/index.js.map +0 -1
  70. package/src/rules/no-deprecated-cipher-method/index.d.ts +0 -23
  71. package/src/rules/no-deprecated-cipher-method/index.js.map +0 -1
  72. package/src/rules/no-dynamic-algorithm-selection/index.d.ts +0 -26
  73. package/src/rules/no-dynamic-algorithm-selection/index.js.map +0 -1
  74. package/src/rules/no-dynamic-dependency-loading/index.d.ts +0 -12
  75. package/src/rules/no-dynamic-dependency-loading/index.js.map +0 -1
  76. package/src/rules/no-dynamic-require/index.d.ts +0 -21
  77. package/src/rules/no-dynamic-require/index.js.map +0 -1
  78. package/src/rules/no-ecb-mode/index.d.ts +0 -23
  79. package/src/rules/no-ecb-mode/index.js.map +0 -1
  80. package/src/rules/no-insecure-key-derivation/index.d.ts +0 -24
  81. package/src/rules/no-insecure-key-derivation/index.js.map +0 -1
  82. package/src/rules/no-insecure-rsa-padding/index.d.ts +0 -24
  83. package/src/rules/no-insecure-rsa-padding/index.js.map +0 -1
  84. package/src/rules/no-math-random-crypto/index.d.ts +0 -26
  85. package/src/rules/no-math-random-crypto/index.js.map +0 -1
  86. package/src/rules/no-self-signed-certs/index.d.ts +0 -23
  87. package/src/rules/no-self-signed-certs/index.js.map +0 -1
  88. package/src/rules/no-sha1-hash/index.d.ts +0 -24
  89. package/src/rules/no-sha1-hash/index.js.map +0 -1
  90. package/src/rules/no-shell-injection/index.d.ts +0 -20
  91. package/src/rules/no-shell-injection/index.js.map +0 -1
  92. package/src/rules/no-ssrf/index.d.ts +0 -25
  93. package/src/rules/no-ssrf/index.js.map +0 -1
  94. package/src/rules/no-static-iv/index.d.ts +0 -23
  95. package/src/rules/no-static-iv/index.js.map +0 -1
  96. package/src/rules/no-timing-unsafe-compare/index.d.ts +0 -23
  97. package/src/rules/no-timing-unsafe-compare/index.js.map +0 -1
  98. package/src/rules/no-toctou-vulnerability/index.d.ts +0 -26
  99. package/src/rules/no-toctou-vulnerability/index.js.map +0 -1
  100. package/src/rules/no-unsafe-buffer-alloc/index.d.ts +0 -47
  101. package/src/rules/no-unsafe-buffer-alloc/index.js.map +0 -1
  102. package/src/rules/no-unsafe-dynamic-require/index.d.ts +0 -19
  103. package/src/rules/no-unsafe-dynamic-require/index.js.map +0 -1
  104. package/src/rules/no-weak-cipher-algorithm/index.d.ts +0 -25
  105. package/src/rules/no-weak-cipher-algorithm/index.js.map +0 -1
  106. package/src/rules/no-weak-hash-algorithm/index.d.ts +0 -25
  107. package/src/rules/no-weak-hash-algorithm/index.js.map +0 -1
  108. package/src/rules/no-zip-slip/index.d.ts +0 -35
  109. package/src/rules/no-zip-slip/index.js.map +0 -1
  110. package/src/rules/prefer-native-crypto/index.d.ts +0 -23
  111. package/src/rules/prefer-native-crypto/index.js.map +0 -1
  112. package/src/rules/require-dependency-integrity/index.d.ts +0 -12
  113. package/src/rules/require-dependency-integrity/index.js.map +0 -1
  114. package/src/rules/require-secure-credential-storage/index.d.ts +0 -12
  115. package/src/rules/require-secure-credential-storage/index.js.map +0 -1
  116. package/src/rules/require-secure-deletion/index.d.ts +0 -17
  117. package/src/rules/require-secure-deletion/index.js.map +0 -1
  118. package/src/rules/require-storage-encryption/index.d.ts +0 -12
  119. package/src/rules/require-storage-encryption/index.js.map +0 -1
  120. package/src/types/index.js.map +0 -1
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noDynamicCommandString = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const ARGV_FUNCTIONS = new Set([
6
+ 'spawn',
7
+ 'spawnSync',
8
+ 'execFile',
9
+ 'execFileSync',
10
+ 'fork',
11
+ ]);
12
+ const POSIX_COMMAND_FLAGS = new Set(['-c']);
13
+ const CMD_COMMAND_FLAGS = new Set(['/c', '/C', '/k', '/K']);
14
+ const POWERSHELL_COMMAND_FLAGS = new Set([
15
+ '-Command',
16
+ '-command',
17
+ '-c',
18
+ '-EncodedCommand',
19
+ '-encodedcommand',
20
+ '-e',
21
+ '-ec',
22
+ ]);
23
+ const SHELL_COMMAND_FLAGS = {
24
+ sh: POSIX_COMMAND_FLAGS,
25
+ bash: POSIX_COMMAND_FLAGS,
26
+ zsh: POSIX_COMMAND_FLAGS,
27
+ dash: POSIX_COMMAND_FLAGS,
28
+ ksh: POSIX_COMMAND_FLAGS,
29
+ busybox: POSIX_COMMAND_FLAGS,
30
+ cmd: CMD_COMMAND_FLAGS,
31
+ 'cmd.exe': CMD_COMMAND_FLAGS,
32
+ powershell: POWERSHELL_COMMAND_FLAGS,
33
+ 'powershell.exe': POWERSHELL_COMMAND_FLAGS,
34
+ pwsh: POWERSHELL_COMMAND_FLAGS,
35
+ };
36
+ const COMMAND_RUNNERS = new Set([
37
+ 'execaCommand',
38
+ 'execaCommandSync',
39
+ '$.raw',
40
+ ]);
41
+ function basename(command) {
42
+ const segments = command.split(/[\\/]/);
43
+ return segments[segments.length - 1];
44
+ }
45
+ function isAssembledString(node) {
46
+ if (node.type === eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral) {
47
+ return node.expressions.length > 0;
48
+ }
49
+ if (node.type === eslint_devkit_1.AST_NODE_TYPES.BinaryExpression) {
50
+ return node.operator === '+';
51
+ }
52
+ return (node.type === eslint_devkit_1.AST_NODE_TYPES.Identifier ||
53
+ node.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression ||
54
+ node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression);
55
+ }
56
+ function calleeName(callee) {
57
+ if (callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier)
58
+ return callee.name;
59
+ if (callee.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression)
60
+ return null;
61
+ if (callee.property.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier)
62
+ return null;
63
+ if (callee.computed)
64
+ return null;
65
+ if (callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
66
+ callee.object.name === '$') {
67
+ return `$.${callee.property.name}`;
68
+ }
69
+ return callee.property.name;
70
+ }
71
+ exports.noDynamicCommandString = (0, eslint_devkit_1.createRule)({
72
+ name: 'no-dynamic-command-string',
73
+ meta: {
74
+ type: 'problem',
75
+ docs: {
76
+ url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-dynamic-command-string.md',
77
+ description: 'Disallow dynamically assembled command strings passed to a shell flag or to a command-runner that does not escape (CWE-77)',
78
+ cwe: 'CWE-77',
79
+ cvss: 9.8,
80
+ confidence: 'high',
81
+ },
82
+ messages: {
83
+ shellFlagInjection: (0, eslint_devkit_1.formatLLMMessage)({
84
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
85
+ issueName: 'Command Injection Through Shell Flag (CWE-77)',
86
+ cwe: 'CWE-77',
87
+ cvss: 9.8,
88
+ description: '{{fn}}("{{shell}}", ["{{flag}}", …]) hands a dynamically built string to {{shell}}, which parses it as a command line. The argument array looks parameterized but everything after {{flag}} is re-parsed — `;`, `&&`, backticks and `$()` all execute.',
89
+ severity: 'CRITICAL',
90
+ fix: 'Invoke the target program directly with its own argument array — spawn("kill", [String(pid)]) — instead of routing it through a shell.',
91
+ documentationLink: 'https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html',
92
+ }),
93
+ commandStringInterpolation: (0, eslint_devkit_1.formatLLMMessage)({
94
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
95
+ issueName: 'Interpolated Command Line (CWE-77)',
96
+ cwe: 'CWE-77',
97
+ cvss: 9.8,
98
+ description: '{{fn}}() takes a whole command line and does NOT escape interpolated values (unlike the execa/zx tagged-template forms). Any special character in the interpolated value changes which command runs.',
99
+ severity: 'CRITICAL',
100
+ fix: 'Use the tagged-template or array form that escapes for you: execa("git", ["clone", url]) or await $`git clone ${url}`.',
101
+ documentationLink: 'https://cwe.mitre.org/data/definitions/77.html',
102
+ }),
103
+ },
104
+ schema: [
105
+ {
106
+ type: 'object',
107
+ properties: {
108
+ extraCommandRunners: {
109
+ type: 'array',
110
+ items: { type: 'string' },
111
+ description: 'Extra functions that accept a full command line without escaping',
112
+ },
113
+ },
114
+ additionalProperties: false,
115
+ },
116
+ ],
117
+ },
118
+ defaultOptions: [{}],
119
+ create(context, [options]) {
120
+ const { extraCommandRunners } = options;
121
+ const runners = new Set([
122
+ ...COMMAND_RUNNERS,
123
+ ...(extraCommandRunners ?? []),
124
+ ]);
125
+ function checkShellFlag(node, fn) {
126
+ const command = node.arguments[0];
127
+ if (!command ||
128
+ command.type !== eslint_devkit_1.AST_NODE_TYPES.Literal ||
129
+ typeof command.value !== 'string') {
130
+ return;
131
+ }
132
+ const shell = basename(command.value);
133
+ const commandFlags = SHELL_COMMAND_FLAGS[shell.toLowerCase()];
134
+ if (!commandFlags)
135
+ return;
136
+ const argv = node.arguments[1];
137
+ if (!argv || argv.type !== eslint_devkit_1.AST_NODE_TYPES.ArrayExpression)
138
+ return;
139
+ for (let i = 0; i < argv.elements.length - 1; i += 1) {
140
+ const flag = argv.elements[i];
141
+ if (!flag || flag.type !== eslint_devkit_1.AST_NODE_TYPES.Literal)
142
+ continue;
143
+ if (typeof flag.value !== 'string')
144
+ continue;
145
+ if (!commandFlags.has(flag.value))
146
+ continue;
147
+ const commandString = argv.elements[i + 1];
148
+ if (!commandString)
149
+ continue;
150
+ if (!isAssembledString(commandString))
151
+ continue;
152
+ context.report({
153
+ node: commandString,
154
+ messageId: 'shellFlagInjection',
155
+ data: { fn, shell, flag: flag.value },
156
+ });
157
+ return;
158
+ }
159
+ }
160
+ function checkCommandRunner(node, fn) {
161
+ const commandLine = node.arguments[0];
162
+ if (!commandLine)
163
+ return;
164
+ if (commandLine.type === eslint_devkit_1.AST_NODE_TYPES.Literal)
165
+ return;
166
+ if (!isAssembledString(commandLine))
167
+ return;
168
+ context.report({
169
+ node: commandLine,
170
+ messageId: 'commandStringInterpolation',
171
+ data: { fn },
172
+ });
173
+ }
174
+ return {
175
+ CallExpression(node) {
176
+ const fn = calleeName(node.callee);
177
+ if (!fn)
178
+ return;
179
+ if (ARGV_FUNCTIONS.has(fn)) {
180
+ checkShellFlag(node, fn);
181
+ return;
182
+ }
183
+ if (runners.has(fn)) {
184
+ checkCommandRunner(node, fn);
185
+ }
186
+ },
187
+ TaggedTemplateExpression(node) {
188
+ const fn = calleeName(node.tag);
189
+ if (!fn || !runners.has(fn))
190
+ return;
191
+ if (node.quasi.expressions.length === 0)
192
+ return;
193
+ context.report({
194
+ node: node.quasi,
195
+ messageId: 'commandStringInterpolation',
196
+ data: { fn },
197
+ });
198
+ },
199
+ };
200
+ },
201
+ });
@@ -1,16 +1,6 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  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
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
5
  exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
16
6
  name: 'no-dynamic-dependency-loading',
@@ -39,7 +29,6 @@ exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
39
29
  create(context) {
40
30
  return {
41
31
  CallExpression(node) {
42
- // Dynamic require
43
32
  if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
44
33
  node.callee.name === 'require' &&
45
34
  node.arguments[0]?.type !== eslint_devkit_1.AST_NODE_TYPES.Literal) {
@@ -47,7 +36,6 @@ exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
47
36
  }
48
37
  },
49
38
  ImportExpression(node) {
50
- // Dynamic import()
51
39
  if (node.source.type !== 'Literal') {
52
40
  context.report({ node, messageId: 'violationDetected' });
53
41
  }
@@ -55,4 +43,3 @@ exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
55
43
  };
56
44
  },
57
45
  });
58
- //# sourceMappingURL=index.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noDynamicRequire = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -75,7 +70,6 @@ exports.noDynamicRequire = (0, eslint_devkit_1.createRule)({
75
70
  }
76
71
  return false;
77
72
  }
78
- // oxlint-disable-next-line consistent-function-scoping
79
73
  function isStaticLiteral(node) {
80
74
  return node.type === 'Literal' && typeof node.value === 'string';
81
75
  }
@@ -88,12 +82,9 @@ exports.noDynamicRequire = (0, eslint_devkit_1.createRule)({
88
82
  if (isInAllowedContext()) {
89
83
  return;
90
84
  }
91
- // Check if it's a static literal
92
85
  if (isStaticLiteral(requireArg)) {
93
- // Static requires are allowed
94
86
  return;
95
87
  }
96
- // Report dynamic require
97
88
  context.report({
98
89
  node: requireArg,
99
90
  messageId: 'dynamicRequire',
@@ -103,4 +94,3 @@ exports.noDynamicRequire = (0, eslint_devkit_1.createRule)({
103
94
  };
104
95
  },
105
96
  });
106
- //# sourceMappingURL=index.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noEcbMode = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -72,7 +67,6 @@ exports.noEcbMode = (0, eslint_devkit_1.createRule)({
72
67
  if (isTestFile)
73
68
  return;
74
69
  const cipherMethods = new Set(['createCipher', 'createCipheriv', 'createDecipher', 'createDecipheriv']);
75
- // Check for crypto.createCipher*() pattern
76
70
  const isCipherCall = (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
77
71
  node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
78
72
  cipherMethods.has(node.callee.property.name)) ||
@@ -112,4 +106,3 @@ exports.noEcbMode = (0, eslint_devkit_1.createRule)({
112
106
  };
113
107
  },
114
108
  });
115
- //# sourceMappingURL=index.js.map
@@ -1,13 +1,7 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noInsecureKeyDerivation = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
- // OWASP 2023 recommendations
11
5
  const DEFAULT_MIN_ITERATIONS = 100000;
12
6
  exports.noInsecureKeyDerivation = (0, eslint_devkit_1.createRule)({
13
7
  name: 'no-insecure-key-derivation',
@@ -77,15 +71,12 @@ exports.noInsecureKeyDerivation = (0, eslint_devkit_1.createRule)({
77
71
  create(context, [options = {}]) {
78
72
  const { minIterations = DEFAULT_MIN_ITERATIONS } = options;
79
73
  function checkCallExpression(node) {
80
- // Check for crypto.pbkdf2() or crypto.pbkdf2Sync()
81
74
  const isPbkdf2Call = (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
82
75
  node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
83
76
  (node.callee.property.name === 'pbkdf2' || node.callee.property.name === 'pbkdf2Sync')) ||
84
77
  (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
85
78
  (node.callee.name === 'pbkdf2' || node.callee.name === 'pbkdf2Sync'));
86
79
  if (isPbkdf2Call) {
87
- // pbkdf2(password, salt, iterations, keylen, digest, callback)
88
- // iterations is the 3rd argument (index 2)
89
80
  const iterationsArg = node.arguments[2];
90
81
  if (iterationsArg?.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof iterationsArg.value === 'number') {
91
82
  const iterations = iterationsArg.value;
@@ -116,4 +107,3 @@ exports.noInsecureKeyDerivation = (0, eslint_devkit_1.createRule)({
116
107
  };
117
108
  },
118
109
  });
119
- //# sourceMappingURL=index.js.map
@@ -1,13 +1,7 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noInsecureRsaPadding = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
- // Constants for PKCS#1 v1.5 padding (insecure)
11
5
  const PKCS1_PADDING_NAMES = new Set([
12
6
  'RSA_PKCS1_PADDING',
13
7
  'constants.RSA_PKCS1_PADDING',
@@ -70,7 +64,6 @@ exports.noInsecureRsaPadding = (0, eslint_devkit_1.createRule)({
70
64
  function checkCallExpression(node) {
71
65
  if (isTestFile)
72
66
  return;
73
- // Check for privateDecrypt, publicDecrypt, privateEncrypt, publicEncrypt
74
67
  const rsaMethods = new Set(['privateDecrypt', 'publicDecrypt', 'privateEncrypt', 'publicEncrypt']);
75
68
  const isRsaCall = (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
76
69
  node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
@@ -79,7 +72,6 @@ exports.noInsecureRsaPadding = (0, eslint_devkit_1.createRule)({
79
72
  rsaMethods.has(node.callee.name));
80
73
  if (isRsaCall && node.arguments.length >= 1) {
81
74
  const keyArg = node.arguments[0];
82
- // Check if first argument is an object with padding property
83
75
  if (keyArg.type === eslint_devkit_1.AST_NODE_TYPES.ObjectExpression) {
84
76
  for (const prop of keyArg.properties) {
85
77
  if (prop.type === eslint_devkit_1.AST_NODE_TYPES.Property &&
@@ -110,4 +102,3 @@ exports.noInsecureRsaPadding = (0, eslint_devkit_1.createRule)({
110
102
  };
111
103
  },
112
104
  });
113
- //# sourceMappingURL=index.js.map
@@ -1,13 +1,7 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noMathRandomCrypto = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
- // Variable names that suggest cryptographic usage
11
5
  const CRYPTO_VARIABLE_PATTERNS = [
12
6
  /token/i,
13
7
  /key/i,
@@ -29,7 +23,6 @@ const CRYPTO_VARIABLE_PATTERNS = [
29
23
  /code/i,
30
24
  /verify/i,
31
25
  ];
32
- // Function names that suggest cryptographic usage
33
26
  const CRYPTO_FUNCTION_PATTERNS = [
34
27
  /generate.*token/i,
35
28
  /generate.*key/i,
@@ -104,10 +97,8 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
104
97
  const filename = context.filename;
105
98
  const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
106
99
  function isCryptoContext(node) {
107
- // Check variable declaration context
108
100
  let current = node.parent;
109
101
  while (current) {
110
- // Check variable names
111
102
  if (current.type === eslint_devkit_1.AST_NODE_TYPES.VariableDeclarator) {
112
103
  if (current.id.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
113
104
  const varName = current.id.name;
@@ -116,14 +107,12 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
116
107
  }
117
108
  }
118
109
  }
119
- // Check function names
120
110
  if (current.type === eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration && current.id) {
121
111
  const funcName = current.id.name;
122
112
  if (CRYPTO_FUNCTION_PATTERNS.some((p) => p.test(funcName))) {
123
113
  return true;
124
114
  }
125
115
  }
126
- // Check assignment to crypto-named property
127
116
  if (current.type === eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression) {
128
117
  if (current.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
129
118
  current.left.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
@@ -133,7 +122,6 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
133
122
  }
134
123
  }
135
124
  }
136
- // Check object property
137
125
  if (current.type === eslint_devkit_1.AST_NODE_TYPES.Property) {
138
126
  if (current.key.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
139
127
  const propName = current.key.name;
@@ -142,7 +130,6 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
142
130
  }
143
131
  }
144
132
  }
145
- // Check return in crypto-named function
146
133
  if (current.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement) {
147
134
  const func = findContainingFunction(current);
148
135
  if (func) {
@@ -177,13 +164,11 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
177
164
  CallExpression(node) {
178
165
  if (isTestFile)
179
166
  return;
180
- // Check for Math.random()
181
167
  if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
182
168
  node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
183
169
  node.callee.object.name === 'Math' &&
184
170
  node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
185
171
  node.callee.property.name === 'random') {
186
- // Check if used in cryptographic context
187
172
  if (isCryptoContext(node)) {
188
173
  context.report({
189
174
  node,
@@ -191,7 +176,7 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
191
176
  suggest: [
192
177
  {
193
178
  messageId: 'useRandomBytes',
194
- fix: () => null, // Complex refactoring
179
+ fix: () => null,
195
180
  },
196
181
  {
197
182
  messageId: 'useRandomUUID',
@@ -205,4 +190,3 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
205
190
  };
206
191
  },
207
192
  });
208
- //# sourceMappingURL=index.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noSelfSignedCerts = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -63,7 +58,6 @@ exports.noSelfSignedCerts = (0, eslint_devkit_1.createRule)({
63
58
  function checkProperty(node) {
64
59
  if (isTestFile)
65
60
  return;
66
- // Check for rejectUnauthorized: false
67
61
  if (node.key.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
68
62
  node.key.name === 'rejectUnauthorized' &&
69
63
  node.value.type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
@@ -85,7 +79,6 @@ exports.noSelfSignedCerts = (0, eslint_devkit_1.createRule)({
85
79
  function checkAssignmentExpression(node) {
86
80
  if (isTestFile)
87
81
  return;
88
- // Check for process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
89
82
  if (node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
90
83
  node.left.object.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
91
84
  node.left.object.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
@@ -102,7 +95,7 @@ exports.noSelfSignedCerts = (0, eslint_devkit_1.createRule)({
102
95
  suggest: [
103
96
  {
104
97
  messageId: 'enableValidation',
105
- fix: () => null, // Should remove the assignment
98
+ fix: () => null,
106
99
  },
107
100
  ],
108
101
  });
@@ -115,4 +108,3 @@ exports.noSelfSignedCerts = (0, eslint_devkit_1.createRule)({
115
108
  };
116
109
  },
117
110
  });
118
- //# sourceMappingURL=index.js.map
@@ -1,9 +1,4 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noSha1Hash = void 0;
9
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
@@ -68,13 +63,11 @@ exports.noSha1Hash = (0, eslint_devkit_1.createRule)({
68
63
  const { allowInTests = false } = options;
69
64
  const filename = context.filename;
70
65
  const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
71
- // Track if sha1 was imported from crypto-hash
72
66
  let sha1ImportedFromCryptoHash = false;
73
67
  return {
74
68
  ImportDeclaration(node) {
75
69
  if (isTestFile)
76
70
  return;
77
- // Check for: import { sha1 } from 'crypto-hash'
78
71
  if (node.source.value === 'crypto-hash') {
79
72
  for (const specifier of node.specifiers) {
80
73
  if (specifier.type === eslint_devkit_1.AST_NODE_TYPES.ImportSpecifier &&
@@ -106,7 +99,6 @@ exports.noSha1Hash = (0, eslint_devkit_1.createRule)({
106
99
  CallExpression(node) {
107
100
  if (isTestFile)
108
101
  return;
109
- // Check for sha1() call if imported from crypto-hash
110
102
  if (sha1ImportedFromCryptoHash &&
111
103
  node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
112
104
  node.callee.name === 'sha1') {
@@ -127,4 +119,3 @@ exports.noSha1Hash = (0, eslint_devkit_1.createRule)({
127
119
  };
128
120
  },
129
121
  });
130
- //# sourceMappingURL=index.js.map
@@ -1,24 +1,7 @@
1
1
  "use strict";
2
- /**
3
- * ESLint Rule: no-shell-injection
4
- * CWE-78: OS Command Injection
5
- *
6
- * Fires when child_process shell-execution functions receive a first
7
- * argument built via string concatenation or template literal expressions.
8
- *
9
- * Detection: structural-api. The rule checks the SHAPE of the first argument,
10
- * not what value flows into it. exec(`git ${cmd}`) fires regardless of what
11
- * `cmd` contains — the concatenation itself is the signal.
12
- *
13
- * Does NOT fire on:
14
- * - exec('literal command') — static string, no injection surface
15
- * - spawn('cmd', [args]) — args array is the safe parameterization form
16
- * - exec(variable) — indirect; data-flow analysis required, out of scope
17
- */
18
2
  Object.defineProperty(exports, "__esModule", { value: true });
19
3
  exports.noShellInjection = void 0;
20
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
21
- /** Shell-execution functions from child_process that run the first arg as a shell command. */
22
5
  const SHELL_EXEC_FUNCTIONS = new Set([
23
6
  'exec', 'execSync',
24
7
  ]);
@@ -64,11 +47,9 @@ exports.noShellInjection = (0, eslint_devkit_1.createRule)({
64
47
  CallExpression(node) {
65
48
  const callee = node.callee;
66
49
  let fnName = null;
67
- // exec('cmd') / execSync('cmd') — bare call
68
50
  if (callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
69
51
  fnName = callee.name;
70
52
  }
71
- // require('child_process').exec('cmd') — member access
72
53
  else if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
73
54
  callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
74
55
  fnName = callee.property.name;
@@ -85,4 +66,3 @@ exports.noShellInjection = (0, eslint_devkit_1.createRule)({
85
66
  };
86
67
  },
87
68
  });
88
- //# sourceMappingURL=index.js.map