eslint-plugin-secure-coding 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/AGENTS.md +196 -0
  2. package/CHANGELOG.md +105 -0
  3. package/LICENSE +23 -0
  4. package/README.md +377 -0
  5. package/package.json +80 -0
  6. package/src/index.d.ts +32 -0
  7. package/src/index.js +345 -0
  8. package/src/index.js.map +1 -0
  9. package/src/rules/security/database-injection.d.ts +13 -0
  10. package/src/rules/security/database-injection.js +407 -0
  11. package/src/rules/security/database-injection.js.map +1 -0
  12. package/src/rules/security/detect-child-process.d.ts +11 -0
  13. package/src/rules/security/detect-child-process.js +460 -0
  14. package/src/rules/security/detect-child-process.js.map +1 -0
  15. package/src/rules/security/detect-eval-with-expression.d.ts +9 -0
  16. package/src/rules/security/detect-eval-with-expression.js +393 -0
  17. package/src/rules/security/detect-eval-with-expression.js.map +1 -0
  18. package/src/rules/security/detect-non-literal-fs-filename.d.ts +7 -0
  19. package/src/rules/security/detect-non-literal-fs-filename.js +322 -0
  20. package/src/rules/security/detect-non-literal-fs-filename.js.map +1 -0
  21. package/src/rules/security/detect-non-literal-regexp.d.ts +9 -0
  22. package/src/rules/security/detect-non-literal-regexp.js +387 -0
  23. package/src/rules/security/detect-non-literal-regexp.js.map +1 -0
  24. package/src/rules/security/detect-object-injection.d.ts +11 -0
  25. package/src/rules/security/detect-object-injection.js +411 -0
  26. package/src/rules/security/detect-object-injection.js.map +1 -0
  27. package/src/rules/security/no-buffer-overread.d.ts +14 -0
  28. package/src/rules/security/no-buffer-overread.js +519 -0
  29. package/src/rules/security/no-buffer-overread.js.map +1 -0
  30. package/src/rules/security/no-clickjacking.d.ts +10 -0
  31. package/src/rules/security/no-clickjacking.js +381 -0
  32. package/src/rules/security/no-clickjacking.js.map +1 -0
  33. package/src/rules/security/no-directive-injection.d.ts +12 -0
  34. package/src/rules/security/no-directive-injection.js +446 -0
  35. package/src/rules/security/no-directive-injection.js.map +1 -0
  36. package/src/rules/security/no-document-cookie.d.ts +5 -0
  37. package/src/rules/security/no-document-cookie.js +90 -0
  38. package/src/rules/security/no-document-cookie.js.map +1 -0
  39. package/src/rules/security/no-electron-security-issues.d.ts +10 -0
  40. package/src/rules/security/no-electron-security-issues.js +421 -0
  41. package/src/rules/security/no-electron-security-issues.js.map +1 -0
  42. package/src/rules/security/no-exposed-sensitive-data.d.ts +11 -0
  43. package/src/rules/security/no-exposed-sensitive-data.js +341 -0
  44. package/src/rules/security/no-exposed-sensitive-data.js.map +1 -0
  45. package/src/rules/security/no-format-string-injection.d.ts +17 -0
  46. package/src/rules/security/no-format-string-injection.js +653 -0
  47. package/src/rules/security/no-format-string-injection.js.map +1 -0
  48. package/src/rules/security/no-graphql-injection.d.ts +12 -0
  49. package/src/rules/security/no-graphql-injection.js +410 -0
  50. package/src/rules/security/no-graphql-injection.js.map +1 -0
  51. package/src/rules/security/no-hardcoded-credentials.d.ts +26 -0
  52. package/src/rules/security/no-hardcoded-credentials.js +377 -0
  53. package/src/rules/security/no-hardcoded-credentials.js.map +1 -0
  54. package/src/rules/security/no-improper-sanitization.d.ts +12 -0
  55. package/src/rules/security/no-improper-sanitization.js +408 -0
  56. package/src/rules/security/no-improper-sanitization.js.map +1 -0
  57. package/src/rules/security/no-improper-type-validation.d.ts +10 -0
  58. package/src/rules/security/no-improper-type-validation.js +420 -0
  59. package/src/rules/security/no-improper-type-validation.js.map +1 -0
  60. package/src/rules/security/no-insecure-comparison.d.ts +7 -0
  61. package/src/rules/security/no-insecure-comparison.js +125 -0
  62. package/src/rules/security/no-insecure-comparison.js.map +1 -0
  63. package/src/rules/security/no-insecure-cookie-settings.d.ts +9 -0
  64. package/src/rules/security/no-insecure-cookie-settings.js +305 -0
  65. package/src/rules/security/no-insecure-cookie-settings.js.map +1 -0
  66. package/src/rules/security/no-insecure-jwt.d.ts +10 -0
  67. package/src/rules/security/no-insecure-jwt.js +338 -0
  68. package/src/rules/security/no-insecure-jwt.js.map +1 -0
  69. package/src/rules/security/no-insecure-redirects.d.ts +7 -0
  70. package/src/rules/security/no-insecure-redirects.js +215 -0
  71. package/src/rules/security/no-insecure-redirects.js.map +1 -0
  72. package/src/rules/security/no-insufficient-postmessage-validation.d.ts +14 -0
  73. package/src/rules/security/no-insufficient-postmessage-validation.js +390 -0
  74. package/src/rules/security/no-insufficient-postmessage-validation.js.map +1 -0
  75. package/src/rules/security/no-insufficient-random.d.ts +9 -0
  76. package/src/rules/security/no-insufficient-random.js +207 -0
  77. package/src/rules/security/no-insufficient-random.js.map +1 -0
  78. package/src/rules/security/no-ldap-injection.d.ts +10 -0
  79. package/src/rules/security/no-ldap-injection.js +449 -0
  80. package/src/rules/security/no-ldap-injection.js.map +1 -0
  81. package/src/rules/security/no-missing-authentication.d.ts +13 -0
  82. package/src/rules/security/no-missing-authentication.js +322 -0
  83. package/src/rules/security/no-missing-authentication.js.map +1 -0
  84. package/src/rules/security/no-missing-cors-check.d.ts +9 -0
  85. package/src/rules/security/no-missing-cors-check.js +449 -0
  86. package/src/rules/security/no-missing-cors-check.js.map +1 -0
  87. package/src/rules/security/no-missing-csrf-protection.d.ts +11 -0
  88. package/src/rules/security/no-missing-csrf-protection.js +183 -0
  89. package/src/rules/security/no-missing-csrf-protection.js.map +1 -0
  90. package/src/rules/security/no-missing-security-headers.d.ts +7 -0
  91. package/src/rules/security/no-missing-security-headers.js +217 -0
  92. package/src/rules/security/no-missing-security-headers.js.map +1 -0
  93. package/src/rules/security/no-privilege-escalation.d.ts +13 -0
  94. package/src/rules/security/no-privilege-escalation.js +321 -0
  95. package/src/rules/security/no-privilege-escalation.js.map +1 -0
  96. package/src/rules/security/no-redos-vulnerable-regex.d.ts +7 -0
  97. package/src/rules/security/no-redos-vulnerable-regex.js +307 -0
  98. package/src/rules/security/no-redos-vulnerable-regex.js.map +1 -0
  99. package/src/rules/security/no-sensitive-data-exposure.d.ts +11 -0
  100. package/src/rules/security/no-sensitive-data-exposure.js +251 -0
  101. package/src/rules/security/no-sensitive-data-exposure.js.map +1 -0
  102. package/src/rules/security/no-sql-injection.d.ts +10 -0
  103. package/src/rules/security/no-sql-injection.js +332 -0
  104. package/src/rules/security/no-sql-injection.js.map +1 -0
  105. package/src/rules/security/no-timing-attack.d.ts +10 -0
  106. package/src/rules/security/no-timing-attack.js +358 -0
  107. package/src/rules/security/no-timing-attack.js.map +1 -0
  108. package/src/rules/security/no-toctou-vulnerability.d.ts +7 -0
  109. package/src/rules/security/no-toctou-vulnerability.js +165 -0
  110. package/src/rules/security/no-toctou-vulnerability.js.map +1 -0
  111. package/src/rules/security/no-unchecked-loop-condition.d.ts +12 -0
  112. package/src/rules/security/no-unchecked-loop-condition.js +635 -0
  113. package/src/rules/security/no-unchecked-loop-condition.js.map +1 -0
  114. package/src/rules/security/no-unencrypted-transmission.d.ts +11 -0
  115. package/src/rules/security/no-unencrypted-transmission.js +237 -0
  116. package/src/rules/security/no-unencrypted-transmission.js.map +1 -0
  117. package/src/rules/security/no-unescaped-url-parameter.d.ts +9 -0
  118. package/src/rules/security/no-unescaped-url-parameter.js +266 -0
  119. package/src/rules/security/no-unescaped-url-parameter.js.map +1 -0
  120. package/src/rules/security/no-unlimited-resource-allocation.d.ts +12 -0
  121. package/src/rules/security/no-unlimited-resource-allocation.js +659 -0
  122. package/src/rules/security/no-unlimited-resource-allocation.js.map +1 -0
  123. package/src/rules/security/no-unsafe-deserialization.d.ts +10 -0
  124. package/src/rules/security/no-unsafe-deserialization.js +501 -0
  125. package/src/rules/security/no-unsafe-deserialization.js.map +1 -0
  126. package/src/rules/security/no-unsafe-dynamic-require.d.ts +5 -0
  127. package/src/rules/security/no-unsafe-dynamic-require.js +107 -0
  128. package/src/rules/security/no-unsafe-dynamic-require.js.map +1 -0
  129. package/src/rules/security/no-unsafe-regex-construction.d.ts +9 -0
  130. package/src/rules/security/no-unsafe-regex-construction.js +292 -0
  131. package/src/rules/security/no-unsafe-regex-construction.js.map +1 -0
  132. package/src/rules/security/no-unsanitized-html.d.ts +9 -0
  133. package/src/rules/security/no-unsanitized-html.js +347 -0
  134. package/src/rules/security/no-unsanitized-html.js.map +1 -0
  135. package/src/rules/security/no-unvalidated-user-input.d.ts +9 -0
  136. package/src/rules/security/no-unvalidated-user-input.js +418 -0
  137. package/src/rules/security/no-unvalidated-user-input.js.map +1 -0
  138. package/src/rules/security/no-weak-crypto.d.ts +11 -0
  139. package/src/rules/security/no-weak-crypto.js +350 -0
  140. package/src/rules/security/no-weak-crypto.js.map +1 -0
  141. package/src/rules/security/no-weak-password-recovery.d.ts +12 -0
  142. package/src/rules/security/no-weak-password-recovery.js +401 -0
  143. package/src/rules/security/no-weak-password-recovery.js.map +1 -0
  144. package/src/rules/security/no-xpath-injection.d.ts +10 -0
  145. package/src/rules/security/no-xpath-injection.js +487 -0
  146. package/src/rules/security/no-xpath-injection.js.map +1 -0
  147. package/src/rules/security/no-xxe-injection.d.ts +7 -0
  148. package/src/rules/security/no-xxe-injection.js +270 -0
  149. package/src/rules/security/no-xxe-injection.js.map +1 -0
  150. package/src/rules/security/no-zip-slip.d.ts +9 -0
  151. package/src/rules/security/no-zip-slip.js +446 -0
  152. package/src/rules/security/no-zip-slip.js.map +1 -0
  153. package/src/types/index.d.ts +131 -0
  154. package/src/types/index.js +18 -0
  155. package/src/types/index.js.map +1 -0
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noPrivilegeEscalation = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ /**
7
+ * Common role check patterns
8
+ */
9
+ const DEFAULT_ROLE_CHECK_PATTERNS = [
10
+ 'hasRole',
11
+ 'checkRole',
12
+ 'isAdmin',
13
+ 'isAuthorized',
14
+ 'hasPermission',
15
+ 'checkPermission',
16
+ 'verifyRole',
17
+ 'requireRole',
18
+ ];
19
+ /**
20
+ * Common user input patterns
21
+ */
22
+ const DEFAULT_USER_INPUT_PATTERNS = [
23
+ /\breq\.(body|query|params)\b/,
24
+ /\brequest\.(body|query|params)\b/,
25
+ /\buserInput\b/,
26
+ /\binput\b/,
27
+ ];
28
+ /**
29
+ * Check if a string matches any ignore pattern
30
+ */
31
+ function matchesIgnorePattern(text, patterns) {
32
+ return patterns.some(pattern => {
33
+ try {
34
+ const regex = new RegExp(pattern, 'i');
35
+ return regex.test(text);
36
+ }
37
+ catch {
38
+ // Invalid regex - treat as literal string match
39
+ return text.toLowerCase().includes(pattern.toLowerCase());
40
+ }
41
+ });
42
+ }
43
+ /**
44
+ * Check if a node contains user input patterns
45
+ */
46
+ function containsUserInput(node, sourceCode, userInputPatterns) {
47
+ const text = sourceCode.getText(node);
48
+ return userInputPatterns.some(pattern => pattern.test(text));
49
+ }
50
+ /**
51
+ * Check if a node is inside a role check call
52
+ */
53
+ function isInsideRoleCheck(node, sourceCode, roleCheckPatterns) {
54
+ let current = node;
55
+ while (current) {
56
+ // Check if current is inside an IfStatement with role check in condition
57
+ if (current.parent && current.parent.type === 'IfStatement') {
58
+ const ifStmt = current.parent;
59
+ const conditionText = sourceCode.getText(ifStmt.test);
60
+ // Check if condition contains role check patterns
61
+ if (roleCheckPatterns.some(pattern => conditionText.toLowerCase().includes(pattern.toLowerCase()))) {
62
+ return true;
63
+ }
64
+ /* c8 ignore start -- redundant check: conditionText pattern match above catches these cases first */
65
+ // Check if condition is a CallExpression with role check
66
+ if (ifStmt.test.type === 'CallExpression') {
67
+ const callExpr = ifStmt.test;
68
+ const callee = callExpr.callee;
69
+ if (callee.type === 'Identifier') {
70
+ const calleeName = callee.name.toLowerCase();
71
+ if (roleCheckPatterns.some(pattern => calleeName.includes(pattern.toLowerCase()))) {
72
+ return true;
73
+ }
74
+ }
75
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
76
+ const propertyName = callee.property.name.toLowerCase();
77
+ if (roleCheckPatterns.some(pattern => propertyName.includes(pattern.toLowerCase()))) {
78
+ return true;
79
+ }
80
+ }
81
+ }
82
+ /* c8 ignore stop */
83
+ }
84
+ // Check if current is inside a ConditionalExpression (ternary) with role check
85
+ if (current.parent && current.parent.type === 'ConditionalExpression') {
86
+ const condExpr = current.parent;
87
+ const testText = sourceCode.getText(condExpr.test);
88
+ // Check if test contains role check patterns
89
+ if (roleCheckPatterns.some(pattern => testText.toLowerCase().includes(pattern.toLowerCase()))) {
90
+ return true;
91
+ }
92
+ /* c8 ignore start -- redundant check: testText pattern match above catches these cases first */
93
+ // Check if test is a CallExpression with role check
94
+ if (condExpr.test.type === 'CallExpression') {
95
+ const callExpr = condExpr.test;
96
+ const callee = callExpr.callee;
97
+ if (callee.type === 'Identifier') {
98
+ const calleeName = callee.name.toLowerCase();
99
+ if (roleCheckPatterns.some(pattern => calleeName.includes(pattern.toLowerCase()))) {
100
+ return true;
101
+ }
102
+ }
103
+ }
104
+ /* c8 ignore stop */
105
+ }
106
+ // Check if current is inside a CallExpression with role check
107
+ if (current.parent && current.parent.type === 'CallExpression') {
108
+ const callExpr = current.parent;
109
+ const callee = callExpr.callee;
110
+ if (callee.type === 'Identifier') {
111
+ const calleeName = callee.name.toLowerCase();
112
+ if (roleCheckPatterns.some(pattern => calleeName.includes(pattern.toLowerCase()))) {
113
+ return true;
114
+ }
115
+ }
116
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
117
+ const propertyName = callee.property.name.toLowerCase();
118
+ if (roleCheckPatterns.some(pattern => propertyName.includes(pattern.toLowerCase()))) {
119
+ return true;
120
+ }
121
+ }
122
+ }
123
+ // Traverse up the AST
124
+ if ('parent' in current && current.parent) {
125
+ current = current.parent;
126
+ }
127
+ else {
128
+ break;
129
+ }
130
+ }
131
+ return false;
132
+ }
133
+ exports.noPrivilegeEscalation = (0, eslint_devkit_2.createRule)({
134
+ name: 'no-privilege-escalation',
135
+ meta: {
136
+ type: 'problem',
137
+ docs: {
138
+ description: 'Detects potential privilege escalation vulnerabilities',
139
+ },
140
+ hasSuggestions: true,
141
+ messages: {
142
+ privilegeEscalation: (0, eslint_devkit_1.formatLLMMessage)({
143
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
144
+ issueName: 'Privilege Escalation',
145
+ cwe: 'CWE-269',
146
+ description: 'Potential privilege escalation: {{issue}} - user input used without role validation',
147
+ severity: 'HIGH',
148
+ fix: 'Add role check before using user input: if (!hasRole(user, requiredRole)) throw new Error("Unauthorized");',
149
+ documentationLink: 'https://cwe.mitre.org/data/definitions/269.html',
150
+ }),
151
+ addRoleCheck: (0, eslint_devkit_1.formatLLMMessage)({
152
+ icon: eslint_devkit_1.MessageIcons.INFO,
153
+ issueName: 'Add Role Check',
154
+ description: 'Add role check before privilege operations',
155
+ severity: 'LOW',
156
+ fix: 'if (!hasRole(user, requiredRole)) throw new Error("Unauthorized")',
157
+ documentationLink: 'https://cwe.mitre.org/data/definitions/269.html',
158
+ }),
159
+ },
160
+ schema: [
161
+ {
162
+ type: 'object',
163
+ properties: {
164
+ allowInTests: {
165
+ type: 'boolean',
166
+ default: false,
167
+ description: 'Allow privilege escalation patterns in test files',
168
+ },
169
+ testFilePattern: {
170
+ type: 'string',
171
+ default: '\\.(test|spec)\\.(ts|tsx|js|jsx)$',
172
+ description: 'Test file pattern regex string',
173
+ },
174
+ roleCheckPatterns: {
175
+ type: 'array',
176
+ items: { type: 'string' },
177
+ default: DEFAULT_ROLE_CHECK_PATTERNS,
178
+ description: 'Role check patterns to recognize',
179
+ },
180
+ userInputPatterns: {
181
+ type: 'array',
182
+ items: { type: 'string' },
183
+ default: [],
184
+ description: 'Additional user input patterns to check (regex strings)',
185
+ },
186
+ ignorePatterns: {
187
+ type: 'array',
188
+ items: { type: 'string' },
189
+ default: [],
190
+ description: 'Additional patterns to ignore',
191
+ },
192
+ },
193
+ additionalProperties: false,
194
+ },
195
+ ],
196
+ },
197
+ defaultOptions: [
198
+ {
199
+ allowInTests: false,
200
+ testFilePattern: '\\.(test|spec)\\.(ts|tsx|js|jsx)$',
201
+ roleCheckPatterns: DEFAULT_ROLE_CHECK_PATTERNS,
202
+ userInputPatterns: [],
203
+ ignorePatterns: [],
204
+ },
205
+ ],
206
+ create(context, [options = {}]) {
207
+ const { allowInTests = false, testFilePattern = '\\.(test|spec)\\.(ts|tsx|js|jsx)$', roleCheckPatterns = DEFAULT_ROLE_CHECK_PATTERNS, userInputPatterns: additionalUserInputPatterns = [], ignorePatterns = [], } = options;
208
+ const filename = context.getFilename();
209
+ const testFileRegex = new RegExp(testFilePattern);
210
+ const isTestFile = allowInTests && testFileRegex.test(filename);
211
+ const sourceCode = context.sourceCode || context.sourceCode;
212
+ // Combine default and additional user input patterns
213
+ const userInputPatterns = [
214
+ ...DEFAULT_USER_INPUT_PATTERNS,
215
+ ...additionalUserInputPatterns.map(pattern => new RegExp(pattern, 'i')),
216
+ ];
217
+ /**
218
+ * Check AssignmentExpression for privilege escalation
219
+ */
220
+ function checkAssignmentExpression(node) {
221
+ if (isTestFile) {
222
+ return;
223
+ }
224
+ // Check for role assignment from user input
225
+ // Pattern: user.role = req.body.role
226
+ if (node.left.type === 'MemberExpression' &&
227
+ node.left.property.type === 'Identifier') {
228
+ const propertyName = node.left.property.name.toLowerCase();
229
+ // Check if it's a role/permission related property
230
+ if (['role', 'permission', 'privilege', 'access', 'level'].includes(propertyName)) {
231
+ const text = sourceCode.getText(node);
232
+ // Check if it matches any ignore pattern
233
+ if (matchesIgnorePattern(text, ignorePatterns)) {
234
+ return;
235
+ }
236
+ // Check if right side contains user input
237
+ if (containsUserInput(node.right, sourceCode, userInputPatterns)) {
238
+ // Check if it's inside a role check
239
+ if (!isInsideRoleCheck(node, sourceCode, roleCheckPatterns)) {
240
+ context.report({
241
+ node: node,
242
+ messageId: 'privilegeEscalation',
243
+ data: {
244
+ issue: `Role assignment from user input: ${sourceCode.getText(node.left)} = ${sourceCode.getText(node.right)}`,
245
+ },
246
+ suggest: [
247
+ {
248
+ messageId: 'addRoleCheck',
249
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
250
+ fix: (_fixer) => null,
251
+ },
252
+ ],
253
+ });
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ /**
260
+ * Check CallExpression for privilege operations with user input
261
+ */
262
+ function checkCallExpression(node) {
263
+ if (isTestFile) {
264
+ return;
265
+ }
266
+ // Check for privilege-related function calls with user input
267
+ const callee = node.callee;
268
+ let isPrivilegeOperation = false;
269
+ let operationName = '';
270
+ if (callee.type === 'Identifier') {
271
+ const calleeName = callee.name.toLowerCase();
272
+ if (['setrole', 'grant', 'revoke', 'elevate', 'promote'].some(op => calleeName.includes(op))) {
273
+ isPrivilegeOperation = true;
274
+ operationName = callee.name;
275
+ }
276
+ }
277
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
278
+ const propertyName = callee.property.name.toLowerCase();
279
+ if (['setrole', 'grant', 'revoke', 'elevate', 'promote', 'updaterole'].some(op => propertyName.includes(op))) {
280
+ isPrivilegeOperation = true;
281
+ operationName = propertyName;
282
+ }
283
+ }
284
+ if (isPrivilegeOperation) {
285
+ const text = sourceCode.getText(node);
286
+ // Check if it matches any ignore pattern
287
+ if (matchesIgnorePattern(text, ignorePatterns)) {
288
+ return;
289
+ }
290
+ // Check if any argument contains user input
291
+ for (const arg of node.arguments) {
292
+ if (containsUserInput(arg, sourceCode, userInputPatterns)) {
293
+ // Check if it's inside a role check
294
+ if (!isInsideRoleCheck(node, sourceCode, roleCheckPatterns)) {
295
+ context.report({
296
+ node: node,
297
+ messageId: 'privilegeEscalation',
298
+ data: {
299
+ issue: `Privilege operation (${operationName}) with user input without role validation`,
300
+ },
301
+ suggest: [
302
+ {
303
+ messageId: 'addRoleCheck',
304
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
305
+ fix: (_fixer) => null,
306
+ },
307
+ ],
308
+ });
309
+ return; // Report once per call
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ return {
316
+ AssignmentExpression: checkAssignmentExpression,
317
+ CallExpression: checkCallExpression,
318
+ };
319
+ },
320
+ });
321
+ //# sourceMappingURL=no-privilege-escalation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-privilege-escalation.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-secure-coding/src/rules/security/no-privilege-escalation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface Options {
2
+ /** Allow certain common patterns. Default: false */
3
+ allowCommonPatterns?: boolean;
4
+ /** Maximum pattern length to analyze. Default: 500 */
5
+ maxPatternLength?: number;
6
+ }
7
+ export declare const noRedosVulnerableRegex: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
@@ -0,0 +1,307 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noRedosVulnerableRegex = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ // Type guard for regex literal nodes
7
+ const isRegExpLiteral = (node) => {
8
+ return node.type === 'Literal' && Object.prototype.hasOwnProperty.call(node, 'regex');
9
+ };
10
+ const REDOS_PATTERNS = [
11
+ {
12
+ pattern: /\([^)]*\+\)\+|\([^)]*\*\)\*|\([^)]*\?\)\?/,
13
+ name: 'Nested Quantifiers',
14
+ description: 'Nested quantifiers like (a+)+, (a*)*, (a?)? cause exponential backtracking',
15
+ example: {
16
+ bad: '/(a+)+b/',
17
+ good: '/(?>a+)b/ or /a+b/'
18
+ },
19
+ fix: 'Use atomic groups (?>...) or restructure to avoid nesting',
20
+ severity: 'critical'
21
+ },
22
+ {
23
+ pattern: /\([^)]*\+[^)]*\)\+|\([^)]*\*[^)]*\)\*/,
24
+ name: 'Nested Repetition',
25
+ description: 'Quantifiers nested within groups with quantifiers',
26
+ example: {
27
+ bad: '/(x+)+y/',
28
+ good: '/x+y/'
29
+ },
30
+ fix: 'Flatten nested quantifiers',
31
+ severity: 'critical'
32
+ },
33
+ {
34
+ pattern: /\([^)]*\|[^)]*\)\+|\([^)]*\|[^)]*\)\*/,
35
+ name: 'Alternation with Quantifier',
36
+ description: 'Alternation groups with quantifiers can cause backtracking',
37
+ example: {
38
+ bad: '/(a|b)+c/',
39
+ good: '/[ab]+c/'
40
+ },
41
+ fix: 'Use character classes instead of alternation when possible',
42
+ severity: 'high'
43
+ },
44
+ {
45
+ pattern: /\.\*\.\*|\.\+\+\.\+/,
46
+ name: 'Nested Wildcards',
47
+ description: 'Nested wildcard quantifiers cause catastrophic backtracking',
48
+ example: {
49
+ bad: '/.*.*/',
50
+ good: '/.*/ or be more specific'
51
+ },
52
+ fix: 'Remove redundant wildcards or be more specific',
53
+ severity: 'critical'
54
+ },
55
+ {
56
+ pattern: /\([^)]*\)\{[0-9]+,\}[^)]*\([^)]*\)\{[0-9]+,\}/,
57
+ name: 'Multiple Repetition Groups',
58
+ description: 'Multiple repetition groups can cause exponential backtracking',
59
+ example: {
60
+ bad: '/(a{2,})+(b{2,})+/',
61
+ good: 'Restructure to avoid nested repetitions'
62
+ },
63
+ fix: 'Restructure regex to avoid nested repetitions',
64
+ severity: 'high'
65
+ }
66
+ ];
67
+ /**
68
+ * Check if a regex pattern contains ReDoS vulnerabilities
69
+ */
70
+ function hasReDoSVulnerability(pattern) {
71
+ for (const redosPattern of REDOS_PATTERNS) {
72
+ if (redosPattern.pattern.test(pattern)) {
73
+ return redosPattern;
74
+ }
75
+ }
76
+ // Additional checks for common ReDoS patterns
77
+ // Nested quantifiers: (a+)+, (a*)*, (a?)?
78
+ if (/(\([^)]*[+*?][^)]*\)[+*?])/.test(pattern)) {
79
+ return {
80
+ pattern: /\([^)]*[+*?][^)]*\)[+*?]/,
81
+ name: 'Nested Quantifier Pattern',
82
+ description: 'Pattern contains nested quantifiers that can cause exponential backtracking',
83
+ example: {
84
+ bad: pattern.substring(0, 30),
85
+ good: 'Restructure to avoid nested quantifiers'
86
+ },
87
+ fix: 'Use atomic groups or restructure regex',
88
+ severity: 'critical'
89
+ };
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Generate fix suggestions based on the vulnerability
95
+ */
96
+ function generateFixSuggestions(vulnerability) {
97
+ const suggestions = [];
98
+ if (vulnerability.severity === 'critical' || vulnerability.name.includes('Nested')) {
99
+ suggestions.push({
100
+ messageId: 'useAtomicGroups',
101
+ description: vulnerability.fix
102
+ });
103
+ suggestions.push({
104
+ messageId: 'restructureRegex',
105
+ description: 'Restructure the regex to avoid nested quantifiers'
106
+ });
107
+ }
108
+ if (vulnerability.name.includes('Quantifier')) {
109
+ suggestions.push({
110
+ messageId: 'usePossessiveQuantifiers',
111
+ description: 'Use possessive quantifiers (*+, ++, ?+) if supported'
112
+ });
113
+ }
114
+ suggestions.push({
115
+ messageId: 'useSafeLibrary',
116
+ description: 'Consider using safe-regex library to validate patterns'
117
+ });
118
+ return suggestions;
119
+ }
120
+ exports.noRedosVulnerableRegex = (0, eslint_devkit_2.createRule)({
121
+ name: 'no-redos-vulnerable-regex',
122
+ meta: {
123
+ type: 'problem',
124
+ docs: {
125
+ description: 'Detects ReDoS-vulnerable regex patterns in literal regex patterns',
126
+ },
127
+ hasSuggestions: true,
128
+ messages: {
129
+ redosVulnerable: (0, eslint_devkit_1.formatLLMMessage)({
130
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
131
+ issueName: 'ReDoS vulnerable regex',
132
+ cwe: 'CWE-400',
133
+ description: '{{vulnerabilityName}}: {{description}}',
134
+ severity: '{{severity}}',
135
+ fix: '{{fix}}',
136
+ documentationLink: 'https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS',
137
+ }),
138
+ useAtomicGroups: (0, eslint_devkit_1.formatLLMMessage)({
139
+ icon: eslint_devkit_1.MessageIcons.INFO,
140
+ issueName: 'Use Atomic Groups',
141
+ description: 'Use atomic groups to prevent backtracking',
142
+ severity: 'LOW',
143
+ fix: '(?>...) to prevent backtracking',
144
+ documentationLink: 'https://www.regular-expressions.info/atomic.html',
145
+ }),
146
+ usePossessiveQuantifiers: (0, eslint_devkit_1.formatLLMMessage)({
147
+ icon: eslint_devkit_1.MessageIcons.INFO,
148
+ issueName: 'Use Possessive Quantifiers',
149
+ description: 'Use possessive quantifiers',
150
+ severity: 'LOW',
151
+ fix: '*+, ++, ?+ (if supported)',
152
+ documentationLink: 'https://www.regular-expressions.info/possessive.html',
153
+ }),
154
+ restructureRegex: (0, eslint_devkit_1.formatLLMMessage)({
155
+ icon: eslint_devkit_1.MessageIcons.INFO,
156
+ issueName: 'Restructure Regex',
157
+ description: 'Restructure to avoid nested quantifiers',
158
+ severity: 'LOW',
159
+ fix: 'Avoid (a+)+ patterns',
160
+ documentationLink: 'https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS',
161
+ }),
162
+ useSafeLibrary: (0, eslint_devkit_1.formatLLMMessage)({
163
+ icon: eslint_devkit_1.MessageIcons.INFO,
164
+ issueName: 'Use safe-regex',
165
+ description: 'Validate with safe-regex library',
166
+ severity: 'LOW',
167
+ fix: 'if (safeRegex(pattern)) { new RegExp(pattern) }',
168
+ documentationLink: 'https://github.com/substack/safe-regex',
169
+ }),
170
+ },
171
+ schema: [
172
+ {
173
+ type: 'object',
174
+ properties: {
175
+ allowCommonPatterns: {
176
+ type: 'boolean',
177
+ default: false,
178
+ description: 'Allow certain common patterns',
179
+ },
180
+ maxPatternLength: {
181
+ type: 'number',
182
+ default: 500,
183
+ minimum: 1,
184
+ description: 'Maximum pattern length to analyze',
185
+ },
186
+ },
187
+ additionalProperties: false,
188
+ },
189
+ ],
190
+ },
191
+ defaultOptions: [
192
+ {
193
+ allowCommonPatterns: false,
194
+ maxPatternLength: 500,
195
+ },
196
+ ],
197
+ create(context, [options = {}]) {
198
+ const { allowCommonPatterns = false, maxPatternLength = 500 } = options || {};
199
+ /**
200
+ * Check literal regex patterns for ReDoS vulnerabilities
201
+ */
202
+ function checkLiteralRegExp(node) {
203
+ if (!isRegExpLiteral(node)) {
204
+ return;
205
+ }
206
+ const pattern = node.regex.pattern;
207
+ // Skip if pattern is too long (performance)
208
+ if (pattern.length > maxPatternLength) {
209
+ return;
210
+ }
211
+ const vulnerability = hasReDoSVulnerability(pattern);
212
+ if (!vulnerability) {
213
+ return;
214
+ }
215
+ // Allow common patterns if configured
216
+ if (allowCommonPatterns && (vulnerability.severity === 'medium' || vulnerability.name === 'Alternation with Quantifier')) {
217
+ return;
218
+ }
219
+ const suggestions = generateFixSuggestions(vulnerability);
220
+ const severity = vulnerability.severity.toUpperCase();
221
+ context.report({
222
+ node,
223
+ messageId: 'redosVulnerable',
224
+ data: {
225
+ vulnerabilityName: vulnerability.name,
226
+ description: vulnerability.description,
227
+ severity,
228
+ fix: vulnerability.fix,
229
+ },
230
+ suggest: suggestions.map(suggestion => ({
231
+ messageId: suggestion.messageId,
232
+ fix: () => null, // Complex refactoring, cannot auto-fix
233
+ })),
234
+ });
235
+ }
236
+ /**
237
+ * Check new RegExp() calls for ReDoS vulnerabilities
238
+ */
239
+ function checkNewRegExp(node) {
240
+ // Check for new RegExp(pattern) or RegExp(pattern)
241
+ let callee;
242
+ if (node.type === 'NewExpression') {
243
+ callee = node.callee;
244
+ }
245
+ else if (node.type === 'CallExpression') {
246
+ callee = node.callee;
247
+ }
248
+ else {
249
+ /* c8 ignore next */
250
+ return;
251
+ }
252
+ const isRegExp = callee.type === 'Identifier' && callee.name === 'RegExp';
253
+ if (!isRegExp) {
254
+ /* c8 ignore next */
255
+ return;
256
+ }
257
+ // Check if first argument is a string literal
258
+ if (node.arguments.length === 0) {
259
+ /* c8 ignore next */
260
+ return;
261
+ }
262
+ const firstArg = node.arguments[0];
263
+ if (firstArg.type !== 'Literal' || typeof firstArg.value !== 'string') {
264
+ /* c8 ignore next */
265
+ return;
266
+ }
267
+ const pattern = firstArg.value;
268
+ // Skip if pattern is too long (performance)
269
+ if (pattern.length > maxPatternLength) {
270
+ /* c8 ignore next */
271
+ return;
272
+ }
273
+ const vulnerability = hasReDoSVulnerability(pattern);
274
+ if (!vulnerability) {
275
+ /* c8 ignore next */
276
+ return;
277
+ }
278
+ // Allow common patterns if configured
279
+ if (allowCommonPatterns && (vulnerability.severity === 'medium' || vulnerability.name === 'Alternation with Quantifier')) {
280
+ /* c8 ignore next */
281
+ return;
282
+ }
283
+ const suggestions = generateFixSuggestions(vulnerability);
284
+ const severity = vulnerability.severity.toUpperCase();
285
+ context.report({
286
+ node,
287
+ messageId: 'redosVulnerable',
288
+ data: {
289
+ vulnerabilityName: vulnerability.name,
290
+ description: vulnerability.description,
291
+ severity,
292
+ fix: vulnerability.fix,
293
+ },
294
+ suggest: suggestions.map(suggestion => ({
295
+ messageId: suggestion.messageId,
296
+ fix: () => null, // Complex refactoring, cannot auto-fix
297
+ })),
298
+ });
299
+ }
300
+ return {
301
+ Literal: checkLiteralRegExp,
302
+ CallExpression: checkNewRegExp,
303
+ NewExpression: checkNewRegExp,
304
+ };
305
+ },
306
+ });
307
+ //# sourceMappingURL=no-redos-vulnerable-regex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-redos-vulnerable-regex.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-secure-coding/src/rules/security/no-redos-vulnerable-regex.ts"],"names":[],"mappings":"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"}