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,446 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noDirectiveInjection = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ const eslint_devkit_3 = require("@interlace/eslint-devkit");
7
+ exports.noDirectiveInjection = (0, eslint_devkit_1.createRule)({
8
+ name: 'no-directive-injection',
9
+ meta: {
10
+ type: 'problem',
11
+ docs: {
12
+ description: 'Detects directive injection vulnerabilities in templates',
13
+ },
14
+ fixable: 'code',
15
+ hasSuggestions: true,
16
+ messages: {
17
+ directiveInjection: (0, eslint_devkit_2.formatLLMMessage)({
18
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
19
+ issueName: 'Directive Injection',
20
+ cwe: 'CWE-96',
21
+ description: 'User input injected into directive or template',
22
+ severity: '{{severity}}',
23
+ fix: '{{safeAlternative}}',
24
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
25
+ }),
26
+ unsafeDirectiveName: (0, eslint_devkit_2.formatLLMMessage)({
27
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
28
+ issueName: 'Unsafe Directive Name',
29
+ cwe: 'CWE-96',
30
+ description: 'Directive name controlled by user input',
31
+ severity: 'CRITICAL',
32
+ fix: 'Use hardcoded directive names or validate against whitelist',
33
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
34
+ }),
35
+ dynamicDirectiveCreation: (0, eslint_devkit_2.formatLLMMessage)({
36
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
37
+ issueName: 'Dynamic Directive Creation',
38
+ cwe: 'CWE-96',
39
+ description: 'Dynamic creation of directives from user input',
40
+ severity: 'HIGH',
41
+ fix: 'Validate directive names against trusted list',
42
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
43
+ }),
44
+ templateInjection: (0, eslint_devkit_2.formatLLMMessage)({
45
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
46
+ issueName: 'Template Injection',
47
+ cwe: 'CWE-96',
48
+ description: 'User input injected into template content',
49
+ severity: 'HIGH',
50
+ fix: 'Sanitize template input or use safe rendering',
51
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
52
+ }),
53
+ unsafeComponentBinding: (0, eslint_devkit_2.formatLLMMessage)({
54
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
55
+ issueName: 'Unsafe Component Binding',
56
+ cwe: 'CWE-96',
57
+ description: 'Dynamic component binding with user input',
58
+ severity: 'HIGH',
59
+ fix: 'Use component whitelist or validate component names',
60
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
61
+ }),
62
+ userControlledTemplate: (0, eslint_devkit_2.formatLLMMessage)({
63
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
64
+ issueName: 'User Controlled Template',
65
+ cwe: 'CWE-96',
66
+ description: 'Template content controlled by user input',
67
+ severity: 'CRITICAL',
68
+ fix: 'Sanitize template input before compilation',
69
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
70
+ }),
71
+ dangerousInnerHTML: (0, eslint_devkit_2.formatLLMMessage)({
72
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
73
+ issueName: 'Dangerous innerHTML',
74
+ cwe: 'CWE-96',
75
+ description: 'innerHTML set with user-controlled content',
76
+ severity: 'HIGH',
77
+ fix: 'Use textContent or sanitize HTML content',
78
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML',
79
+ }),
80
+ untrustedDirectiveSource: (0, eslint_devkit_2.formatLLMMessage)({
81
+ icon: eslint_devkit_2.MessageIcons.SECURITY,
82
+ issueName: 'Untrusted Directive Source',
83
+ cwe: 'CWE-96',
84
+ description: 'Directive loaded from untrusted source',
85
+ severity: 'MEDIUM',
86
+ fix: 'Load directives from trusted, verified sources',
87
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
88
+ }),
89
+ useTrustedDirectives: (0, eslint_devkit_2.formatLLMMessage)({
90
+ icon: eslint_devkit_2.MessageIcons.INFO,
91
+ issueName: 'Use Trusted Directives',
92
+ description: 'Use only trusted, verified directives',
93
+ severity: 'LOW',
94
+ fix: 'Maintain whitelist of allowed directives',
95
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
96
+ }),
97
+ sanitizeTemplateInput: (0, eslint_devkit_2.formatLLMMessage)({
98
+ icon: eslint_devkit_2.MessageIcons.INFO,
99
+ issueName: 'Sanitize Template Input',
100
+ description: 'Sanitize user input before template processing',
101
+ severity: 'LOW',
102
+ fix: 'Use DOMPurify or equivalent sanitization',
103
+ documentationLink: 'https://github.com/cure53/DOMPurify',
104
+ }),
105
+ validateDirectiveNames: (0, eslint_devkit_2.formatLLMMessage)({
106
+ icon: eslint_devkit_2.MessageIcons.INFO,
107
+ issueName: 'Validate Directive Names',
108
+ description: 'Validate directive names against whitelist',
109
+ severity: 'LOW',
110
+ fix: 'Check directive names before dynamic creation',
111
+ documentationLink: 'https://cwe.mitre.org/data/definitions/96.html',
112
+ }),
113
+ strategyTemplateSanitization: (0, eslint_devkit_2.formatLLMMessage)({
114
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
115
+ issueName: 'Template Sanitization Strategy',
116
+ description: 'Implement template input sanitization',
117
+ severity: 'LOW',
118
+ fix: 'Sanitize all user input before template processing',
119
+ documentationLink: 'https://owasp.org/www-community/xss-filter-evasion-cheatsheet',
120
+ }),
121
+ strategyContentSecurity: (0, eslint_devkit_2.formatLLMMessage)({
122
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
123
+ issueName: 'Content Security Strategy',
124
+ description: 'Use CSP to restrict directive execution',
125
+ severity: 'LOW',
126
+ fix: 'Implement strict CSP with script-src restrictions',
127
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP',
128
+ }),
129
+ strategyInputValidation: (0, eslint_devkit_2.formatLLMMessage)({
130
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
131
+ issueName: 'Input Validation Strategy',
132
+ description: 'Validate all template inputs',
133
+ severity: 'LOW',
134
+ fix: 'Use schema validation for template inputs',
135
+ documentationLink: 'https://joi.dev/',
136
+ })
137
+ },
138
+ schema: [
139
+ {
140
+ type: 'object',
141
+ properties: {
142
+ trustedDirectives: {
143
+ type: 'array',
144
+ items: { type: 'string' },
145
+ default: ['ngIf', 'ngFor', 'ngClass', 'v-if', 'v-for', 'v-bind', 'v-on'],
146
+ },
147
+ userInputVariables: {
148
+ type: 'array',
149
+ items: { type: 'string' },
150
+ default: ['req', 'request', 'body', 'query', 'params', 'input', 'data', 'userInput'],
151
+ },
152
+ frameworks: {
153
+ type: 'array',
154
+ items: { type: 'string' },
155
+ default: ['angular', 'vue', 'react', 'svelte'],
156
+ },
157
+ allowDynamicInComponents: {
158
+ type: 'boolean',
159
+ default: false,
160
+ },
161
+ trustedSanitizers: {
162
+ type: 'array',
163
+ items: { type: 'string' },
164
+ default: [],
165
+ description: 'Additional function names to consider as template sanitizers',
166
+ },
167
+ trustedAnnotations: {
168
+ type: 'array',
169
+ items: { type: 'string' },
170
+ default: [],
171
+ description: 'Additional JSDoc annotations to consider as safe markers',
172
+ },
173
+ strictMode: {
174
+ type: 'boolean',
175
+ default: false,
176
+ description: 'Disable all false positive detection (strict mode)',
177
+ },
178
+ },
179
+ additionalProperties: false,
180
+ },
181
+ ],
182
+ },
183
+ defaultOptions: [
184
+ {
185
+ trustedDirectives: ['ngIf', 'ngFor', 'ngClass', 'v-if', 'v-for', 'v-bind', 'v-on'],
186
+ userInputVariables: ['req', 'request', 'body', 'query', 'params', 'input', 'data', 'userInput'],
187
+ frameworks: ['angular', 'vue', 'react', 'svelte'],
188
+ allowDynamicInComponents: false,
189
+ trustedSanitizers: [],
190
+ trustedAnnotations: [],
191
+ strictMode: false,
192
+ },
193
+ ],
194
+ create(context) {
195
+ const options = context.options[0] || {};
196
+ const { userInputVariables = ['req', 'request', 'body', 'query', 'params', 'input', 'data', 'userInput'], trustedSanitizers = [], trustedAnnotations = [], strictMode = false, } = options;
197
+ const sourceCode = context.sourceCode || context.sourceCode;
198
+ const filename = context.filename || context.getFilename();
199
+ // Create safety checker for false positive detection
200
+ const safetyChecker = (0, eslint_devkit_3.createSafetyChecker)({
201
+ trustedSanitizers,
202
+ trustedAnnotations,
203
+ trustedOrmPatterns: [],
204
+ strictMode,
205
+ });
206
+ /**
207
+ * Check if a variable contains user input
208
+ */
209
+ const isUserInput = (varName) => {
210
+ return userInputVariables.some(input => varName.includes(input));
211
+ };
212
+ return {
213
+ // Check JSX attributes for directive injection
214
+ JSXAttribute(node) {
215
+ const attrName = node.name;
216
+ const attrValue = node.value;
217
+ // Check for dangerouslySetInnerHTML
218
+ if (attrName.type === 'JSXIdentifier' && attrName.name === 'dangerouslySetInnerHTML') {
219
+ if (attrValue && attrValue.type === 'JSXExpressionContainer') {
220
+ const expression = attrValue.expression;
221
+ // Check if the expression contains user input
222
+ const expressionText = sourceCode.getText(expression);
223
+ if (userInputVariables.some(input => expressionText.includes(input))) {
224
+ // FALSE POSITIVE REDUCTION
225
+ if (safetyChecker.isSafe(node, context)) {
226
+ return;
227
+ }
228
+ context.report({
229
+ node: attrValue,
230
+ messageId: 'dangerousInnerHTML',
231
+ data: {
232
+ filePath: filename,
233
+ line: String(node.loc?.start.line ?? 0),
234
+ },
235
+ });
236
+ }
237
+ }
238
+ }
239
+ // Check for dynamic directive names (Angular/Vue style)
240
+ // Check for dynamic directive names (Angular/Vue style)
241
+ const isNamespaceDirective = ((attrName.type === 'JSXNamespacedName' && (attrName.namespace.name === 'v' || attrName.namespace.name === 'ng')) ||
242
+ (attrName.type === 'JSXIdentifier' && (attrName.name.startsWith('ng:') || attrName.name.startsWith('v:'))));
243
+ if (isNamespaceDirective && attrValue) {
244
+ if (attrValue.type === 'JSXExpressionContainer') {
245
+ const expression = attrValue.expression;
246
+ // Check if directive value comes from user input
247
+ if (expression.type === 'Identifier' && isUserInput(expression.name)) {
248
+ // FALSE POSITIVE REDUCTION
249
+ if (safetyChecker.isSafe(node, context)) {
250
+ return;
251
+ }
252
+ context.report({
253
+ node: attrValue,
254
+ messageId: 'directiveInjection',
255
+ data: {
256
+ filePath: filename,
257
+ line: String(node.loc?.start.line ?? 0),
258
+ severity: 'HIGH',
259
+ safeAlternative: 'Use hardcoded directive values or validate user input',
260
+ },
261
+ });
262
+ }
263
+ }
264
+ }
265
+ // Check for dynamic component binding (React/Angular)
266
+ if (attrName.type === 'JSXIdentifier') {
267
+ const attrNameStr = attrName.name;
268
+ // Check for is="" (dynamic component in Vue/Angular)
269
+ if (attrNameStr === 'is' && attrValue) {
270
+ if (attrValue.type === 'JSXExpressionContainer') {
271
+ const expression = attrValue.expression;
272
+ if (expression.type === 'Identifier' && isUserInput(expression.name)) {
273
+ // FALSE POSITIVE REDUCTION
274
+ if (safetyChecker.isSafe(node, context)) {
275
+ return;
276
+ }
277
+ context.report({
278
+ node: attrValue,
279
+ messageId: 'unsafeComponentBinding',
280
+ data: {
281
+ filePath: filename,
282
+ line: String(node.loc?.start.line ?? 0),
283
+ },
284
+ });
285
+ }
286
+ }
287
+ }
288
+ }
289
+ },
290
+ // Check for innerHTML assignments
291
+ AssignmentExpression(node) {
292
+ const left = node.left;
293
+ const right = node.right;
294
+ // Check for element.innerHTML = userInput
295
+ if (left.type === 'MemberExpression' &&
296
+ left.property.type === 'Identifier' &&
297
+ left.property.name === 'innerHTML') {
298
+ // Check if right side contains user input
299
+ const rightText = sourceCode.getText(right);
300
+ if (userInputVariables.some(input => rightText.includes(input))) {
301
+ // FALSE POSITIVE REDUCTION
302
+ if (safetyChecker.isSafe(node, context)) {
303
+ return;
304
+ }
305
+ context.report({
306
+ node: right,
307
+ messageId: 'dangerousInnerHTML',
308
+ data: {
309
+ filePath: filename,
310
+ line: String(node.loc?.start.line ?? 0),
311
+ },
312
+ });
313
+ }
314
+ }
315
+ },
316
+ // Check for template compilation with user input
317
+ CallExpression(node) {
318
+ const callee = node.callee;
319
+ // Check for template compilation functions
320
+ if (callee.type === 'MemberExpression' &&
321
+ callee.property.type === 'Identifier') {
322
+ const methodName = callee.property.name;
323
+ const objectName = callee.object.type === 'Identifier' ? callee.object.name : '';
324
+ // Template compilation functions
325
+ if (['compile', 'template', '$compile', '$interpolate'].includes(methodName) ||
326
+ (objectName === 'Handlebars' && methodName === 'compile') ||
327
+ (objectName === '_' && methodName === 'template')) {
328
+ const args = node.arguments;
329
+ if (args.length > 0) {
330
+ const templateArg = args[0];
331
+ // Check if template comes from user input
332
+ if (templateArg.type === 'Identifier' && isUserInput(templateArg.name)) {
333
+ // FALSE POSITIVE REDUCTION
334
+ if (safetyChecker.isSafe(node, context)) {
335
+ return;
336
+ }
337
+ context.report({
338
+ node: templateArg,
339
+ messageId: 'userControlledTemplate',
340
+ data: {
341
+ filePath: filename,
342
+ line: String(node.loc?.start.line ?? 0),
343
+ },
344
+ });
345
+ }
346
+ }
347
+ }
348
+ // Check for Vue.js v-html directive
349
+ if (objectName === 'Vue' && methodName === 'directive') {
350
+ const args = node.arguments;
351
+ if (args.length >= 2) {
352
+ const directiveName = args[0];
353
+ if (directiveName.type === 'Identifier' && isUserInput(directiveName.name)) {
354
+ // FALSE POSITIVE REDUCTION
355
+ if (safetyChecker.isSafe(node, context)) {
356
+ return;
357
+ }
358
+ context.report({
359
+ node: directiveName,
360
+ messageId: 'unsafeDirectiveName',
361
+ data: {
362
+ filePath: filename,
363
+ line: String(node.loc?.start.line ?? 0),
364
+ },
365
+ });
366
+ }
367
+ }
368
+ }
369
+ }
370
+ // Check for Angular directive creation
371
+ if (callee.type === 'Identifier' && callee.name === 'directive') {
372
+ const args = node.arguments;
373
+ if (args.length >= 2) {
374
+ const directiveName = args[0];
375
+ if (directiveName.type === 'Identifier' && isUserInput(directiveName.name)) {
376
+ // FALSE POSITIVE REDUCTION
377
+ if (safetyChecker.isSafe(node, context)) {
378
+ return;
379
+ }
380
+ context.report({
381
+ node: directiveName,
382
+ messageId: 'dynamicDirectiveCreation',
383
+ data: {
384
+ filePath: filename,
385
+ line: String(node.loc?.start.line ?? 0),
386
+ },
387
+ });
388
+ }
389
+ }
390
+ }
391
+ },
392
+ // Check template literals for injection
393
+ TemplateLiteral(node) {
394
+ // Check if template literal is used dangerously
395
+ let current = node;
396
+ let isInDangerousContext = false;
397
+ while (current && !isInDangerousContext) {
398
+ if (current.type === 'JSXExpressionContainer') {
399
+ // Check if we are inside dangerouslySetInnerHTML attribute
400
+ if (current.parent?.type === 'JSXAttribute' &&
401
+ current.parent.name.type === 'JSXIdentifier' &&
402
+ current.parent.name.name === 'dangerouslySetInnerHTML') {
403
+ isInDangerousContext = true;
404
+ break;
405
+ }
406
+ }
407
+ else if (current.type === 'AssignmentExpression') {
408
+ // Check for innerHTML assignment
409
+ const left = current.left;
410
+ if (left.type === 'MemberExpression' &&
411
+ left.property.type === 'Identifier' &&
412
+ left.property.name === 'innerHTML') {
413
+ isInDangerousContext = true;
414
+ break;
415
+ }
416
+ }
417
+ current = current.parent;
418
+ }
419
+ if (isInDangerousContext) {
420
+ // Check if template contains user input
421
+ const hasUserInput = node.expressions.some((expr) => (expr.type === 'Identifier' && isUserInput(expr.name)) ||
422
+ (expr.type === 'MemberExpression' &&
423
+ expr.object.type === 'Identifier' &&
424
+ isUserInput(expr.object.name)));
425
+ if (hasUserInput) {
426
+ // FALSE POSITIVE REDUCTION
427
+ if (safetyChecker.isSafe(node, context)) {
428
+ return;
429
+ }
430
+ context.report({
431
+ node,
432
+ messageId: 'templateInjection',
433
+ data: {
434
+ filePath: filename,
435
+ line: String(node.loc?.start.line ?? 0),
436
+ severity: 'HIGH',
437
+ safeAlternative: 'Sanitize template input before insertion',
438
+ },
439
+ });
440
+ }
441
+ }
442
+ }
443
+ };
444
+ },
445
+ });
446
+ //# sourceMappingURL=no-directive-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-directive-injection.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-secure-coding/src/rules/security/no-directive-injection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface Options {
2
+ /** Allow reading document.cookie for parsing */
3
+ allowReading?: boolean;
4
+ }
5
+ export declare const noDocumentCookie: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noDocumentCookie = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ exports.noDocumentCookie = (0, eslint_devkit_1.createRule)({
7
+ name: 'no-document-cookie',
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: 'Prevent direct usage of document.cookie - use Cookie Store API or cookie libraries instead',
12
+ },
13
+ hasSuggestions: false,
14
+ messages: {
15
+ noDocumentCookie: (0, eslint_devkit_2.formatLLMMessage)({
16
+ icon: eslint_devkit_2.MessageIcons.WARNING,
17
+ issueName: 'Document Cookie',
18
+ description: 'Avoid direct document.cookie usage',
19
+ severity: 'MEDIUM',
20
+ fix: 'Use Cookie Store API or cookie library instead',
21
+ documentationLink: 'https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-document-cookie.md',
22
+ }),
23
+ },
24
+ schema: [
25
+ {
26
+ type: 'object',
27
+ properties: {
28
+ allowReading: {
29
+ type: 'boolean',
30
+ default: true,
31
+ },
32
+ },
33
+ additionalProperties: false,
34
+ },
35
+ ],
36
+ },
37
+ defaultOptions: [{ allowReading: true }],
38
+ create(context) {
39
+ const [options] = context.options;
40
+ const { allowReading = true } = options || {};
41
+ function isDocumentCookieAccess(node) {
42
+ // Check if this is accessing document.cookie
43
+ return (node.object.type === 'Identifier' &&
44
+ node.object.name === 'document' &&
45
+ ((node.property.type === 'Identifier' && node.property.name === 'cookie') ||
46
+ (node.computed && node.property.type === 'Literal' && node.property.value === 'cookie')));
47
+ }
48
+ function isAssignmentToCookie(node) {
49
+ // Check if this is an assignment to document.cookie
50
+ const parent = node.parent;
51
+ // Check direct assignment
52
+ if (parent?.type === 'AssignmentExpression' && parent.left === node) {
53
+ return true;
54
+ }
55
+ // Check compound assignment (+=, -=, etc.)
56
+ if (parent?.type === 'AssignmentExpression' &&
57
+ parent.operator &&
58
+ parent.operator.includes('=') &&
59
+ parent.left === node) {
60
+ return true;
61
+ }
62
+ // Variable declarator (const/let/var x = document.cookie) - this is reading, not assigning
63
+ if (parent?.type === 'VariableDeclarator' && parent.init === node) {
64
+ return false;
65
+ }
66
+ return false;
67
+ }
68
+ return {
69
+ MemberExpression(node) {
70
+ if (isDocumentCookieAccess(node)) {
71
+ const isAssigning = isAssignmentToCookie(node);
72
+ // If allowReading is true, only flag assignments
73
+ // If allowReading is false, flag everything
74
+ if (allowReading && !isAssigning) {
75
+ return; // Allow reading when option is enabled
76
+ }
77
+ // Flag document.cookie usage
78
+ context.report({
79
+ node,
80
+ messageId: 'noDocumentCookie',
81
+ data: {
82
+ operation: isAssigning ? 'assignment to' : 'reading from',
83
+ },
84
+ });
85
+ }
86
+ },
87
+ };
88
+ },
89
+ });
90
+ //# sourceMappingURL=no-document-cookie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-document-cookie.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-secure-coding/src/rules/security/no-document-cookie.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type SecurityRuleOptions } from '@interlace/eslint-devkit';
2
+ export interface Options extends SecurityRuleOptions {
3
+ /** Allow insecure settings in development */
4
+ allowInDev?: boolean;
5
+ /** Safe preload script patterns */
6
+ safePreloadPatterns?: string[];
7
+ /** Allowed IPC channels */
8
+ allowedIpcChannels?: string[];
9
+ }
10
+ export declare const noElectronSecurityIssues: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;