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.
- package/AGENTS.md +196 -0
- package/CHANGELOG.md +105 -0
- package/LICENSE +23 -0
- package/README.md +377 -0
- package/package.json +80 -0
- package/src/index.d.ts +32 -0
- package/src/index.js +345 -0
- package/src/index.js.map +1 -0
- package/src/rules/security/database-injection.d.ts +13 -0
- package/src/rules/security/database-injection.js +407 -0
- package/src/rules/security/database-injection.js.map +1 -0
- package/src/rules/security/detect-child-process.d.ts +11 -0
- package/src/rules/security/detect-child-process.js +460 -0
- package/src/rules/security/detect-child-process.js.map +1 -0
- package/src/rules/security/detect-eval-with-expression.d.ts +9 -0
- package/src/rules/security/detect-eval-with-expression.js +393 -0
- package/src/rules/security/detect-eval-with-expression.js.map +1 -0
- package/src/rules/security/detect-non-literal-fs-filename.d.ts +7 -0
- package/src/rules/security/detect-non-literal-fs-filename.js +322 -0
- package/src/rules/security/detect-non-literal-fs-filename.js.map +1 -0
- package/src/rules/security/detect-non-literal-regexp.d.ts +9 -0
- package/src/rules/security/detect-non-literal-regexp.js +387 -0
- package/src/rules/security/detect-non-literal-regexp.js.map +1 -0
- package/src/rules/security/detect-object-injection.d.ts +11 -0
- package/src/rules/security/detect-object-injection.js +411 -0
- package/src/rules/security/detect-object-injection.js.map +1 -0
- package/src/rules/security/no-buffer-overread.d.ts +14 -0
- package/src/rules/security/no-buffer-overread.js +519 -0
- package/src/rules/security/no-buffer-overread.js.map +1 -0
- package/src/rules/security/no-clickjacking.d.ts +10 -0
- package/src/rules/security/no-clickjacking.js +381 -0
- package/src/rules/security/no-clickjacking.js.map +1 -0
- package/src/rules/security/no-directive-injection.d.ts +12 -0
- package/src/rules/security/no-directive-injection.js +446 -0
- package/src/rules/security/no-directive-injection.js.map +1 -0
- package/src/rules/security/no-document-cookie.d.ts +5 -0
- package/src/rules/security/no-document-cookie.js +90 -0
- package/src/rules/security/no-document-cookie.js.map +1 -0
- package/src/rules/security/no-electron-security-issues.d.ts +10 -0
- package/src/rules/security/no-electron-security-issues.js +421 -0
- package/src/rules/security/no-electron-security-issues.js.map +1 -0
- package/src/rules/security/no-exposed-sensitive-data.d.ts +11 -0
- package/src/rules/security/no-exposed-sensitive-data.js +341 -0
- package/src/rules/security/no-exposed-sensitive-data.js.map +1 -0
- package/src/rules/security/no-format-string-injection.d.ts +17 -0
- package/src/rules/security/no-format-string-injection.js +653 -0
- package/src/rules/security/no-format-string-injection.js.map +1 -0
- package/src/rules/security/no-graphql-injection.d.ts +12 -0
- package/src/rules/security/no-graphql-injection.js +410 -0
- package/src/rules/security/no-graphql-injection.js.map +1 -0
- package/src/rules/security/no-hardcoded-credentials.d.ts +26 -0
- package/src/rules/security/no-hardcoded-credentials.js +377 -0
- package/src/rules/security/no-hardcoded-credentials.js.map +1 -0
- package/src/rules/security/no-improper-sanitization.d.ts +12 -0
- package/src/rules/security/no-improper-sanitization.js +408 -0
- package/src/rules/security/no-improper-sanitization.js.map +1 -0
- package/src/rules/security/no-improper-type-validation.d.ts +10 -0
- package/src/rules/security/no-improper-type-validation.js +420 -0
- package/src/rules/security/no-improper-type-validation.js.map +1 -0
- package/src/rules/security/no-insecure-comparison.d.ts +7 -0
- package/src/rules/security/no-insecure-comparison.js +125 -0
- package/src/rules/security/no-insecure-comparison.js.map +1 -0
- package/src/rules/security/no-insecure-cookie-settings.d.ts +9 -0
- package/src/rules/security/no-insecure-cookie-settings.js +305 -0
- package/src/rules/security/no-insecure-cookie-settings.js.map +1 -0
- package/src/rules/security/no-insecure-jwt.d.ts +10 -0
- package/src/rules/security/no-insecure-jwt.js +338 -0
- package/src/rules/security/no-insecure-jwt.js.map +1 -0
- package/src/rules/security/no-insecure-redirects.d.ts +7 -0
- package/src/rules/security/no-insecure-redirects.js +215 -0
- package/src/rules/security/no-insecure-redirects.js.map +1 -0
- package/src/rules/security/no-insufficient-postmessage-validation.d.ts +14 -0
- package/src/rules/security/no-insufficient-postmessage-validation.js +390 -0
- package/src/rules/security/no-insufficient-postmessage-validation.js.map +1 -0
- package/src/rules/security/no-insufficient-random.d.ts +9 -0
- package/src/rules/security/no-insufficient-random.js +207 -0
- package/src/rules/security/no-insufficient-random.js.map +1 -0
- package/src/rules/security/no-ldap-injection.d.ts +10 -0
- package/src/rules/security/no-ldap-injection.js +449 -0
- package/src/rules/security/no-ldap-injection.js.map +1 -0
- package/src/rules/security/no-missing-authentication.d.ts +13 -0
- package/src/rules/security/no-missing-authentication.js +322 -0
- package/src/rules/security/no-missing-authentication.js.map +1 -0
- package/src/rules/security/no-missing-cors-check.d.ts +9 -0
- package/src/rules/security/no-missing-cors-check.js +449 -0
- package/src/rules/security/no-missing-cors-check.js.map +1 -0
- package/src/rules/security/no-missing-csrf-protection.d.ts +11 -0
- package/src/rules/security/no-missing-csrf-protection.js +183 -0
- package/src/rules/security/no-missing-csrf-protection.js.map +1 -0
- package/src/rules/security/no-missing-security-headers.d.ts +7 -0
- package/src/rules/security/no-missing-security-headers.js +217 -0
- package/src/rules/security/no-missing-security-headers.js.map +1 -0
- package/src/rules/security/no-privilege-escalation.d.ts +13 -0
- package/src/rules/security/no-privilege-escalation.js +321 -0
- package/src/rules/security/no-privilege-escalation.js.map +1 -0
- package/src/rules/security/no-redos-vulnerable-regex.d.ts +7 -0
- package/src/rules/security/no-redos-vulnerable-regex.js +307 -0
- package/src/rules/security/no-redos-vulnerable-regex.js.map +1 -0
- package/src/rules/security/no-sensitive-data-exposure.d.ts +11 -0
- package/src/rules/security/no-sensitive-data-exposure.js +251 -0
- package/src/rules/security/no-sensitive-data-exposure.js.map +1 -0
- package/src/rules/security/no-sql-injection.d.ts +10 -0
- package/src/rules/security/no-sql-injection.js +332 -0
- package/src/rules/security/no-sql-injection.js.map +1 -0
- package/src/rules/security/no-timing-attack.d.ts +10 -0
- package/src/rules/security/no-timing-attack.js +358 -0
- package/src/rules/security/no-timing-attack.js.map +1 -0
- package/src/rules/security/no-toctou-vulnerability.d.ts +7 -0
- package/src/rules/security/no-toctou-vulnerability.js +165 -0
- package/src/rules/security/no-toctou-vulnerability.js.map +1 -0
- package/src/rules/security/no-unchecked-loop-condition.d.ts +12 -0
- package/src/rules/security/no-unchecked-loop-condition.js +635 -0
- package/src/rules/security/no-unchecked-loop-condition.js.map +1 -0
- package/src/rules/security/no-unencrypted-transmission.d.ts +11 -0
- package/src/rules/security/no-unencrypted-transmission.js +237 -0
- package/src/rules/security/no-unencrypted-transmission.js.map +1 -0
- package/src/rules/security/no-unescaped-url-parameter.d.ts +9 -0
- package/src/rules/security/no-unescaped-url-parameter.js +266 -0
- package/src/rules/security/no-unescaped-url-parameter.js.map +1 -0
- package/src/rules/security/no-unlimited-resource-allocation.d.ts +12 -0
- package/src/rules/security/no-unlimited-resource-allocation.js +659 -0
- package/src/rules/security/no-unlimited-resource-allocation.js.map +1 -0
- package/src/rules/security/no-unsafe-deserialization.d.ts +10 -0
- package/src/rules/security/no-unsafe-deserialization.js +501 -0
- package/src/rules/security/no-unsafe-deserialization.js.map +1 -0
- package/src/rules/security/no-unsafe-dynamic-require.d.ts +5 -0
- package/src/rules/security/no-unsafe-dynamic-require.js +107 -0
- package/src/rules/security/no-unsafe-dynamic-require.js.map +1 -0
- package/src/rules/security/no-unsafe-regex-construction.d.ts +9 -0
- package/src/rules/security/no-unsafe-regex-construction.js +292 -0
- package/src/rules/security/no-unsafe-regex-construction.js.map +1 -0
- package/src/rules/security/no-unsanitized-html.d.ts +9 -0
- package/src/rules/security/no-unsanitized-html.js +347 -0
- package/src/rules/security/no-unsanitized-html.js.map +1 -0
- package/src/rules/security/no-unvalidated-user-input.d.ts +9 -0
- package/src/rules/security/no-unvalidated-user-input.js +418 -0
- package/src/rules/security/no-unvalidated-user-input.js.map +1 -0
- package/src/rules/security/no-weak-crypto.d.ts +11 -0
- package/src/rules/security/no-weak-crypto.js +350 -0
- package/src/rules/security/no-weak-crypto.js.map +1 -0
- package/src/rules/security/no-weak-password-recovery.d.ts +12 -0
- package/src/rules/security/no-weak-password-recovery.js +401 -0
- package/src/rules/security/no-weak-password-recovery.js.map +1 -0
- package/src/rules/security/no-xpath-injection.d.ts +10 -0
- package/src/rules/security/no-xpath-injection.js +487 -0
- package/src/rules/security/no-xpath-injection.js.map +1 -0
- package/src/rules/security/no-xxe-injection.d.ts +7 -0
- package/src/rules/security/no-xxe-injection.js +270 -0
- package/src/rules/security/no-xxe-injection.js.map +1 -0
- package/src/rules/security/no-zip-slip.d.ts +9 -0
- package/src/rules/security/no-zip-slip.js +446 -0
- package/src/rules/security/no-zip-slip.js.map +1 -0
- package/src/types/index.d.ts +131 -0
- package/src/types/index.js +18 -0
- package/src/types/index.js.map +1 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noMissingCorsCheck = void 0;
|
|
4
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
+
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
+
/**
|
|
7
|
+
* Check if a node is inside a CORS configuration
|
|
8
|
+
* Currently unused - kept for future use
|
|
9
|
+
* @coverage-note This function is intentionally unused and kept for future enhancements.
|
|
10
|
+
* It cannot be tested directly as it's not called by any code path.
|
|
11
|
+
*/
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13
|
+
function isInsideCorsConfig(node, sourceCode, trustedLibraries) {
|
|
14
|
+
let current = node;
|
|
15
|
+
while (current) {
|
|
16
|
+
// Check for CORS middleware usage
|
|
17
|
+
if (current.type === 'CallExpression') {
|
|
18
|
+
const callee = current.callee;
|
|
19
|
+
// Check if it's a CORS middleware call
|
|
20
|
+
if (callee.type === 'Identifier') {
|
|
21
|
+
const calleeName = callee.name.toLowerCase();
|
|
22
|
+
if (['cors', 'use', 'enable'].includes(calleeName)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Check if it's a trusted library call
|
|
27
|
+
if (callee.type === 'MemberExpression') {
|
|
28
|
+
const object = callee.object;
|
|
29
|
+
if (object.type === 'Identifier') {
|
|
30
|
+
const objectName = object.name.toLowerCase();
|
|
31
|
+
if (trustedLibraries.some(lib => objectName.includes(lib.toLowerCase()))) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Check for CORS configuration object
|
|
38
|
+
if (current.type === 'ObjectExpression') {
|
|
39
|
+
const text = sourceCode.getText(current);
|
|
40
|
+
if (/\b(origin|credentials|allowedOrigins|allowedHeaders)\s*:/i.test(text)) {
|
|
41
|
+
// Check if it has proper validation (not just '*')
|
|
42
|
+
if (!/\borigin\s*:\s*['"]\*['"]/i.test(text)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Traverse up the AST
|
|
48
|
+
if ('parent' in current && current.parent) {
|
|
49
|
+
current = current.parent;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if a string matches any ignore pattern
|
|
59
|
+
*/
|
|
60
|
+
function matchesIgnorePattern(text, ignorePatterns) {
|
|
61
|
+
return ignorePatterns.some(pattern => {
|
|
62
|
+
try {
|
|
63
|
+
const regex = new RegExp(pattern, 'i');
|
|
64
|
+
return regex.test(text);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.noMissingCorsCheck = (0, eslint_devkit_2.createRule)({
|
|
72
|
+
name: 'no-missing-cors-check',
|
|
73
|
+
meta: {
|
|
74
|
+
type: 'problem',
|
|
75
|
+
docs: {
|
|
76
|
+
description: 'Detects missing CORS validation (wildcard CORS, missing origin check)',
|
|
77
|
+
},
|
|
78
|
+
hasSuggestions: true,
|
|
79
|
+
messages: {
|
|
80
|
+
missingCorsCheck: (0, eslint_devkit_1.formatLLMMessage)({
|
|
81
|
+
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
82
|
+
issueName: 'Missing CORS Validation',
|
|
83
|
+
cwe: 'CWE-346',
|
|
84
|
+
description: 'Missing CORS validation detected: {{issue}}',
|
|
85
|
+
severity: 'HIGH',
|
|
86
|
+
fix: '{{safeAlternative}}',
|
|
87
|
+
documentationLink: 'https://cwe.mitre.org/data/definitions/346.html',
|
|
88
|
+
}),
|
|
89
|
+
useOriginValidation: (0, eslint_devkit_1.formatLLMMessage)({
|
|
90
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
91
|
+
issueName: 'Validate Origin',
|
|
92
|
+
description: 'Validate CORS origin',
|
|
93
|
+
severity: 'LOW',
|
|
94
|
+
fix: 'cors({ origin: (origin, cb) => allowedOrigins.includes(origin) ? cb(null, true) : cb(new Error()) })',
|
|
95
|
+
documentationLink: 'https://github.com/expressjs/cors#configuration-options',
|
|
96
|
+
}),
|
|
97
|
+
useCorsMiddleware: (0, eslint_devkit_1.formatLLMMessage)({
|
|
98
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
99
|
+
issueName: 'Use CORS Middleware',
|
|
100
|
+
description: 'Use CORS middleware with origin validation',
|
|
101
|
+
severity: 'LOW',
|
|
102
|
+
fix: 'app.use(cors({ origin: allowedOrigins }))',
|
|
103
|
+
documentationLink: 'https://github.com/expressjs/cors',
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
schema: [
|
|
107
|
+
{
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
allowInTests: {
|
|
111
|
+
type: 'boolean',
|
|
112
|
+
default: false,
|
|
113
|
+
description: 'Allow missing CORS checks in test files',
|
|
114
|
+
},
|
|
115
|
+
trustedLibraries: {
|
|
116
|
+
type: 'array',
|
|
117
|
+
items: { type: 'string' },
|
|
118
|
+
default: [],
|
|
119
|
+
description: 'Custom CORS libraries to trust (wildcard origins in these libraries will not be reported)',
|
|
120
|
+
},
|
|
121
|
+
ignorePatterns: {
|
|
122
|
+
type: 'array',
|
|
123
|
+
items: { type: 'string' },
|
|
124
|
+
default: [],
|
|
125
|
+
description: 'Additional safe patterns to ignore',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
additionalProperties: false,
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
defaultOptions: [
|
|
133
|
+
{
|
|
134
|
+
allowInTests: false,
|
|
135
|
+
trustedLibraries: [], // Empty by default - users can add custom CORS libraries they trust
|
|
136
|
+
ignorePatterns: [],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
create(context, [options = {}]) {
|
|
140
|
+
const { allowInTests = false, trustedLibraries: corsTrustedLibraries = [], ignorePatterns = [], } = options;
|
|
141
|
+
const trustedLibraries = corsTrustedLibraries;
|
|
142
|
+
const filename = context.getFilename();
|
|
143
|
+
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
144
|
+
const sourceCode = context.sourceCode || context.sourceCode;
|
|
145
|
+
function checkLiteral(node) {
|
|
146
|
+
if (isTestFile) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
// Check for wildcard CORS origin
|
|
150
|
+
if (node.value === '*' && typeof node.value === 'string') {
|
|
151
|
+
const text = sourceCode.getText(node);
|
|
152
|
+
// Check if it matches any ignore pattern
|
|
153
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Check if it's in contexts handled by other checkers
|
|
157
|
+
// 1. setHeader/header calls - checkMemberExpression handles these
|
|
158
|
+
// 2. app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
|
|
159
|
+
let shouldSkip = false;
|
|
160
|
+
let current = node;
|
|
161
|
+
while (current && current.parent) {
|
|
162
|
+
current = current.parent;
|
|
163
|
+
if (current.type === 'CallExpression') {
|
|
164
|
+
const callText = sourceCode.getText(current);
|
|
165
|
+
// Check if it's a setHeader/header call with Access-Control-Allow-Origin
|
|
166
|
+
// Skip these - checkMemberExpression handles them
|
|
167
|
+
if (/\b(setHeader|header)\s*\(/i.test(callText) && /\bAccess-Control-Allow-Origin\b/i.test(callText)) {
|
|
168
|
+
shouldSkip = true;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
// Check if it's app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
|
|
172
|
+
if (/\buse\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
|
|
173
|
+
// Check if the literal is in an object property named "origin"
|
|
174
|
+
if (node.parent && node.parent.type === 'Property') {
|
|
175
|
+
const prop = node.parent;
|
|
176
|
+
if (prop.key.type === 'Identifier' && prop.key.name === 'origin') {
|
|
177
|
+
shouldSkip = true;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Skip if it's in a context handled by another checker
|
|
185
|
+
if (shouldSkip) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Check if it's in a CORS-related context
|
|
189
|
+
// Only report if it's actually in a CORS configuration (app.use(cors(...)), etc.)
|
|
190
|
+
// Not just any object with origin: "*"
|
|
191
|
+
let isActualCorsContext = false;
|
|
192
|
+
// Check if it's in app.use(cors(...)) or similar
|
|
193
|
+
current = node;
|
|
194
|
+
while (current && current.parent) {
|
|
195
|
+
current = current.parent;
|
|
196
|
+
if (current.type === 'CallExpression') {
|
|
197
|
+
const callText = sourceCode.getText(current);
|
|
198
|
+
// Check if it's a CORS middleware call
|
|
199
|
+
if (/\b(use|cors)\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
|
|
200
|
+
isActualCorsContext = true;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Also check if it's in an object property with name "origin" or "allowedOrigins"
|
|
206
|
+
// but only if it's in a CORS-related call expression
|
|
207
|
+
if (node.parent && node.parent.type === 'Property') {
|
|
208
|
+
const prop = node.parent;
|
|
209
|
+
if (prop.key.type === 'Identifier') {
|
|
210
|
+
const keyName = prop.key.name.toLowerCase();
|
|
211
|
+
if (keyName === 'origin' || keyName === 'allowedorigins') {
|
|
212
|
+
// Check if this property is in a CORS call context
|
|
213
|
+
let inCorsCall = false;
|
|
214
|
+
let checkNode = prop;
|
|
215
|
+
while (checkNode && checkNode.parent) {
|
|
216
|
+
checkNode = checkNode.parent;
|
|
217
|
+
if (checkNode.type === 'CallExpression') {
|
|
218
|
+
const callText = sourceCode.getText(checkNode);
|
|
219
|
+
if (/\bcors\s*\(/i.test(callText) ||
|
|
220
|
+
(/\buse\s*\(/i.test(callText) && /\bcors/i.test(callText))) {
|
|
221
|
+
inCorsCall = true;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (inCorsCall) {
|
|
227
|
+
// Always report wildcard CORS origin - it's never safe
|
|
228
|
+
context.report({
|
|
229
|
+
node,
|
|
230
|
+
messageId: 'missingCorsCheck',
|
|
231
|
+
data: {
|
|
232
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
233
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
234
|
+
},
|
|
235
|
+
suggest: [
|
|
236
|
+
{
|
|
237
|
+
messageId: 'useOriginValidation',
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
239
|
+
fix: (_fixer) => null,
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Only report if it's in an actual CORS context
|
|
249
|
+
if (isActualCorsContext) {
|
|
250
|
+
// Always report wildcard CORS origin - it's never safe
|
|
251
|
+
context.report({
|
|
252
|
+
node,
|
|
253
|
+
messageId: 'missingCorsCheck',
|
|
254
|
+
data: {
|
|
255
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
256
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
257
|
+
},
|
|
258
|
+
suggest: [
|
|
259
|
+
{
|
|
260
|
+
messageId: 'useOriginValidation',
|
|
261
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
262
|
+
fix: (_fixer) => null,
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function checkCallExpression(node) {
|
|
270
|
+
if (isTestFile) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
// Check for app.use(cors({ origin: "*" })) or similar
|
|
274
|
+
if (node.callee.type === 'MemberExpression') {
|
|
275
|
+
const property = node.callee.property;
|
|
276
|
+
if (property.type === 'Identifier' && property.name === 'use') {
|
|
277
|
+
// Check if CORS is being used
|
|
278
|
+
const text = sourceCode.getText(node);
|
|
279
|
+
// Check if it matches any ignore pattern
|
|
280
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
// Check if it's a CORS middleware call
|
|
284
|
+
// Check for cors() or trusted library calls
|
|
285
|
+
const firstArg = node.arguments.length > 0 ? node.arguments[0] : null;
|
|
286
|
+
let isCorsCall = /\bcors\s*\(/i.test(text);
|
|
287
|
+
if (!isCorsCall && firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
|
|
288
|
+
const callee = firstArg.callee;
|
|
289
|
+
const calleeName = callee.name.toLowerCase();
|
|
290
|
+
// Check if it's the standard 'cors' library or a trusted library
|
|
291
|
+
isCorsCall = calleeName === 'cors' || trustedLibraries.some(lib => {
|
|
292
|
+
return calleeName.includes(lib.toLowerCase());
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// Check if it's a trusted library - skip if explicitly trusted
|
|
296
|
+
let isTrustedLibrary = false;
|
|
297
|
+
if (firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
|
|
298
|
+
const calleeName = firstArg.callee.name.toLowerCase();
|
|
299
|
+
isTrustedLibrary = trustedLibraries.some(lib => calleeName.includes(lib.toLowerCase()));
|
|
300
|
+
}
|
|
301
|
+
if (isTrustedLibrary) {
|
|
302
|
+
return; // Trusted library, skip
|
|
303
|
+
}
|
|
304
|
+
// Check if it's a CORS call
|
|
305
|
+
if (/\bcors\s*\(/i.test(text) || isCorsCall) {
|
|
306
|
+
// Check arguments for wildcard origin
|
|
307
|
+
// For app.use(cors({ origin: "*" })), we need to check the arguments to cors(), not app.use()
|
|
308
|
+
const corsCallArg = firstArg && firstArg.type === 'CallExpression' ? firstArg : null;
|
|
309
|
+
const argsToCheck = corsCallArg ? corsCallArg.arguments : node.arguments;
|
|
310
|
+
for (const arg of argsToCheck) {
|
|
311
|
+
if (arg.type === 'ObjectExpression') {
|
|
312
|
+
// Check for origin property with wildcard value
|
|
313
|
+
for (const prop of arg.properties) {
|
|
314
|
+
if (prop.type === 'Property' &&
|
|
315
|
+
prop.key.type === 'Identifier' &&
|
|
316
|
+
prop.key.name === 'origin' &&
|
|
317
|
+
prop.value.type === 'Literal' &&
|
|
318
|
+
prop.value.value === '*') {
|
|
319
|
+
context.report({
|
|
320
|
+
node: prop.value,
|
|
321
|
+
messageId: 'missingCorsCheck',
|
|
322
|
+
data: {
|
|
323
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
324
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
325
|
+
},
|
|
326
|
+
suggest: [
|
|
327
|
+
{
|
|
328
|
+
messageId: 'useOriginValidation',
|
|
329
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
330
|
+
fix: (_fixer) => null,
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if (arg.type === 'Identifier') {
|
|
338
|
+
// Check if this identifier was assigned an object literal with origin: "*"
|
|
339
|
+
// For cases like: const config = { origin: "*" }; app.use(cors(config));
|
|
340
|
+
const varName = arg.name;
|
|
341
|
+
// Traverse the AST to find the variable declaration
|
|
342
|
+
let current = node;
|
|
343
|
+
while (current) {
|
|
344
|
+
if (current.type === 'Program' || current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') {
|
|
345
|
+
// Search for variable declarations in this scope
|
|
346
|
+
const scopeBody = current.type === 'Program' ? current.body :
|
|
347
|
+
(current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') ?
|
|
348
|
+
(current.body.type === 'BlockStatement' ? current.body.body : []) : [];
|
|
349
|
+
for (const stmt of scopeBody) {
|
|
350
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
351
|
+
for (const declarator of stmt.declarations) {
|
|
352
|
+
if (declarator.id.type === 'Identifier' && declarator.id.name === varName && declarator.init) {
|
|
353
|
+
// Check if init is an object literal with origin: "*"
|
|
354
|
+
if (declarator.init.type === 'ObjectExpression') {
|
|
355
|
+
for (const prop of declarator.init.properties) {
|
|
356
|
+
if (prop.type === 'Property' &&
|
|
357
|
+
prop.key.type === 'Identifier' &&
|
|
358
|
+
prop.key.name === 'origin' &&
|
|
359
|
+
prop.value.type === 'Literal' &&
|
|
360
|
+
prop.value.value === '*') {
|
|
361
|
+
context.report({
|
|
362
|
+
node: arg,
|
|
363
|
+
messageId: 'missingCorsCheck',
|
|
364
|
+
data: {
|
|
365
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
366
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
367
|
+
},
|
|
368
|
+
suggest: [
|
|
369
|
+
{
|
|
370
|
+
messageId: 'useOriginValidation',
|
|
371
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
372
|
+
fix: (_fixer) => null,
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
});
|
|
376
|
+
return; // Found and reported, exit
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
break; // Only check the immediate scope
|
|
385
|
+
}
|
|
386
|
+
if (current.parent) {
|
|
387
|
+
current = current.parent;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function checkMemberExpression(node) {
|
|
400
|
+
if (isTestFile) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// Check for Access-Control-Allow-Origin header without validation
|
|
404
|
+
if (node.property.type === 'Identifier') {
|
|
405
|
+
const propertyName = node.property.name;
|
|
406
|
+
if (propertyName === 'setHeader' || propertyName === 'header') {
|
|
407
|
+
// Check if it matches any ignore pattern
|
|
408
|
+
const text = sourceCode.getText(node);
|
|
409
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
// Check if it's setting CORS headers
|
|
413
|
+
// Need to check the full call expression, not just the member expression
|
|
414
|
+
const parent = node.parent;
|
|
415
|
+
if (parent && parent.type === 'CallExpression') {
|
|
416
|
+
const callText = sourceCode.getText(parent);
|
|
417
|
+
if (/\bAccess-Control-Allow-Origin\b/i.test(callText)) {
|
|
418
|
+
// Check if the value is a wildcard
|
|
419
|
+
const args = parent.arguments;
|
|
420
|
+
if (args.length >= 2 && args[1].type === 'Literal' && args[1].value === '*') {
|
|
421
|
+
context.report({
|
|
422
|
+
node: args[1],
|
|
423
|
+
messageId: 'missingCorsCheck',
|
|
424
|
+
data: {
|
|
425
|
+
issue: 'Wildcard CORS header allows all origins',
|
|
426
|
+
safeAlternative: 'Validate origin before setting header: res.setHeader("Access-Control-Allow-Origin", allowedOrigins.includes(origin) ? origin : "null");',
|
|
427
|
+
},
|
|
428
|
+
suggest: [
|
|
429
|
+
{
|
|
430
|
+
messageId: 'useOriginValidation',
|
|
431
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
432
|
+
fix: (_fixer) => null,
|
|
433
|
+
},
|
|
434
|
+
],
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
Literal: checkLiteral,
|
|
444
|
+
CallExpression: checkCallExpression,
|
|
445
|
+
MemberExpression: checkMemberExpression,
|
|
446
|
+
};
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
//# sourceMappingURL=no-missing-cors-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-missing-cors-check.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-secure-coding/src/rules/security/no-missing-cors-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface Options {
|
|
2
|
+
/** Allow missing CSRF protection in test files. Default: false */
|
|
3
|
+
allowInTests?: boolean;
|
|
4
|
+
/** CSRF middleware patterns to recognize. Default: ['csrf', 'csurf', 'csrfProtection', 'verifyCsrfToken'] */
|
|
5
|
+
csrfMiddlewarePatterns?: string[];
|
|
6
|
+
/** HTTP methods that require CSRF protection. Default: ['post', 'put', 'delete', 'patch'] */
|
|
7
|
+
protectedMethods?: string[];
|
|
8
|
+
/** Additional safe patterns to ignore. Default: [] */
|
|
9
|
+
ignorePatterns?: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare const noMissingCsrfProtection: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|