eslint-plugin-secure-coding 2.3.4 → 2.4.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/CHANGELOG.md +51 -1
- package/README.md +3 -2
- package/package.json +2 -9
- package/src/index.d.ts +1 -1
- package/src/index.js +0 -49
- package/src/types/index.d.ts +4 -29
- package/src/types/index.js +3 -4
- package/src/rules/database-injection/index.d.ts +0 -13
- package/src/rules/database-injection/index.js +0 -406
- package/src/rules/no-credentials-in-storage-api/index.d.ts +0 -6
- package/src/rules/no-credentials-in-storage-api/index.js +0 -54
- package/src/rules/no-document-cookie/index.d.ts +0 -5
- package/src/rules/no-document-cookie/index.js +0 -89
- package/src/rules/no-insecure-cookie-settings/index.d.ts +0 -9
- package/src/rules/no-insecure-cookie-settings/index.js +0 -306
- package/src/rules/no-insecure-jwt/index.d.ts +0 -10
- package/src/rules/no-insecure-jwt/index.js +0 -380
- package/src/rules/no-insufficient-postmessage-validation/index.d.ts +0 -14
- package/src/rules/no-insufficient-postmessage-validation/index.js +0 -392
- package/src/rules/no-insufficient-random/index.d.ts +0 -9
- package/src/rules/no-insufficient-random/index.js +0 -208
- package/src/rules/no-postmessage-origin-wildcard/index.d.ts +0 -8
- package/src/rules/no-postmessage-origin-wildcard/index.js +0 -56
- package/src/rules/no-sql-injection/index.d.ts +0 -10
- package/src/rules/no-sql-injection/index.js +0 -335
- package/src/rules/no-timing-attack/index.d.ts +0 -10
- package/src/rules/no-timing-attack/index.js +0 -447
- package/src/rules/no-unencrypted-local-storage/index.d.ts +0 -8
- package/src/rules/no-unencrypted-local-storage/index.js +0 -61
- package/src/rules/no-unsanitized-html/index.d.ts +0 -9
- package/src/rules/no-unsanitized-html/index.js +0 -335
- package/src/rules/no-weak-crypto/index.d.ts +0 -11
- package/src/rules/no-weak-crypto/index.js +0 -351
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noWeakCrypto = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
-
const WEAK_CRYPTO_PATTERNS = [
|
|
7
|
-
{
|
|
8
|
-
pattern: /\bmd5\b/i,
|
|
9
|
-
name: 'MD5',
|
|
10
|
-
category: 'hash',
|
|
11
|
-
alternatives: ['SHA-256', 'SHA-512', 'SHA-3'],
|
|
12
|
-
example: {
|
|
13
|
-
bad: 'crypto.createHash("md5").update(data)',
|
|
14
|
-
good: 'crypto.createHash("sha256").update(data)'
|
|
15
|
-
},
|
|
16
|
-
effort: '5 minutes'
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
pattern: /\bsha1\b/i,
|
|
20
|
-
name: 'SHA-1',
|
|
21
|
-
category: 'hash',
|
|
22
|
-
alternatives: ['SHA-256', 'SHA-512', 'SHA-3'],
|
|
23
|
-
example: {
|
|
24
|
-
bad: 'crypto.createHash("sha1").update(data)',
|
|
25
|
-
good: 'crypto.createHash("sha256").update(data)'
|
|
26
|
-
},
|
|
27
|
-
effort: '5 minutes'
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
pattern: /\bdes\b/i,
|
|
31
|
-
name: 'DES',
|
|
32
|
-
category: 'encryption',
|
|
33
|
-
alternatives: ['AES-256', 'ChaCha20-Poly1305'],
|
|
34
|
-
example: {
|
|
35
|
-
bad: 'crypto.createCipher("des", key)',
|
|
36
|
-
good: 'crypto.createCipheriv("aes-256-gcm", key, iv)'
|
|
37
|
-
},
|
|
38
|
-
effort: '15 minutes'
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
pattern: /\b3des\b|\btripledes\b/i,
|
|
42
|
-
name: '3DES',
|
|
43
|
-
category: 'encryption',
|
|
44
|
-
alternatives: ['AES-256', 'ChaCha20-Poly1305'],
|
|
45
|
-
example: {
|
|
46
|
-
bad: 'crypto.createCipher("des-ede3", key)',
|
|
47
|
-
good: 'crypto.createCipheriv("aes-256-gcm", key, iv)'
|
|
48
|
-
},
|
|
49
|
-
effort: '15 minutes'
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
pattern: /\brc4\b/i,
|
|
53
|
-
name: 'RC4',
|
|
54
|
-
category: 'encryption',
|
|
55
|
-
alternatives: ['AES-256', 'ChaCha20-Poly1305'],
|
|
56
|
-
example: {
|
|
57
|
-
bad: 'crypto.createCipher("rc4", key)',
|
|
58
|
-
good: 'crypto.createCipheriv("aes-256-gcm", key, iv)'
|
|
59
|
-
},
|
|
60
|
-
effort: '15 minutes'
|
|
61
|
-
}
|
|
62
|
-
];
|
|
63
|
-
/**
|
|
64
|
-
* Check if a string contains a weak crypto algorithm
|
|
65
|
-
*/
|
|
66
|
-
function containsWeakCrypto(value, additionalPatterns) {
|
|
67
|
-
// Check standard patterns
|
|
68
|
-
for (const pattern of WEAK_CRYPTO_PATTERNS) {
|
|
69
|
-
if (pattern.pattern.test(value)) {
|
|
70
|
-
return pattern;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Check additional patterns
|
|
74
|
-
for (const additionalPattern of additionalPatterns) {
|
|
75
|
-
const regex = new RegExp(`\\b${additionalPattern}\\b`, 'i');
|
|
76
|
-
if (regex.test(value)) {
|
|
77
|
-
return {
|
|
78
|
-
pattern: regex,
|
|
79
|
-
name: additionalPattern,
|
|
80
|
-
category: 'hash',
|
|
81
|
-
alternatives: ['SHA-256', 'SHA-512'],
|
|
82
|
-
example: {
|
|
83
|
-
bad: `crypto.createHash("${additionalPattern}").update(data)`,
|
|
84
|
-
good: 'crypto.createHash("sha256").update(data)'
|
|
85
|
-
},
|
|
86
|
-
effort: '10 minutes'
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Generate refactoring suggestions based on the weak crypto pattern
|
|
94
|
-
*/
|
|
95
|
-
function generateRefactoringSteps(pattern, context) {
|
|
96
|
-
const suggestions = [];
|
|
97
|
-
if (pattern.category === 'hash') {
|
|
98
|
-
suggestions.push({
|
|
99
|
-
messageId: 'useSha256',
|
|
100
|
-
fix: `Use SHA-256: crypto.createHash("sha256").update(${context})`
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else if (pattern.category === 'encryption') {
|
|
104
|
-
suggestions.push({
|
|
105
|
-
messageId: 'useAes256',
|
|
106
|
-
fix: `Use AES-256-GCM: crypto.createCipheriv("aes-256-gcm", key, iv)`
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
if (pattern.category === 'password') {
|
|
110
|
-
suggestions.push({
|
|
111
|
-
messageId: 'useBcrypt',
|
|
112
|
-
fix: 'Use bcrypt: bcrypt.hash(password, 10)'
|
|
113
|
-
});
|
|
114
|
-
suggestions.push({
|
|
115
|
-
messageId: 'useScrypt',
|
|
116
|
-
fix: 'Use scrypt: crypto.scrypt(password, salt, 64)'
|
|
117
|
-
});
|
|
118
|
-
suggestions.push({
|
|
119
|
-
messageId: 'useArgon2',
|
|
120
|
-
fix: 'Use Argon2: argon2.hash(password)'
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
return suggestions;
|
|
124
|
-
}
|
|
125
|
-
exports.noWeakCrypto = (0, eslint_devkit_2.createRule)({
|
|
126
|
-
name: 'no-weak-crypto',
|
|
127
|
-
meta: {
|
|
128
|
-
type: 'problem',
|
|
129
|
-
deprecated: true,
|
|
130
|
-
replacedBy: ['@see eslint-plugin-crypto for 24 crypto security rules'],
|
|
131
|
-
docs: {
|
|
132
|
-
description: 'Detects use of weak cryptography algorithms (MD5, SHA1, DES)',
|
|
133
|
-
},
|
|
134
|
-
hasSuggestions: true,
|
|
135
|
-
messages: {
|
|
136
|
-
weakCrypto: (0, eslint_devkit_1.formatLLMMessage)({
|
|
137
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
138
|
-
issueName: 'Weak cryptography',
|
|
139
|
-
cwe: 'CWE-327',
|
|
140
|
-
description: 'Use of weak cryptography algorithm: {{algorithm}}',
|
|
141
|
-
severity: 'CRITICAL',
|
|
142
|
-
fix: '{{safeAlternative}}',
|
|
143
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Weak_Cryptography',
|
|
144
|
-
}),
|
|
145
|
-
useSha256: (0, eslint_devkit_1.formatLLMMessage)({
|
|
146
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
147
|
-
issueName: 'Use SHA-256',
|
|
148
|
-
description: 'Use SHA-256 for hashing',
|
|
149
|
-
severity: 'LOW',
|
|
150
|
-
fix: 'crypto.createHash("sha256").update(data)',
|
|
151
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatehashmethod-options',
|
|
152
|
-
}),
|
|
153
|
-
useBcrypt: (0, eslint_devkit_1.formatLLMMessage)({
|
|
154
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
155
|
-
issueName: 'Use bcrypt',
|
|
156
|
-
description: 'Use bcrypt for password hashing',
|
|
157
|
-
severity: 'LOW',
|
|
158
|
-
fix: 'bcrypt.hash(password, 10)',
|
|
159
|
-
documentationLink: 'https://github.com/kelektiv/node.bcrypt.js',
|
|
160
|
-
}),
|
|
161
|
-
useScrypt: (0, eslint_devkit_1.formatLLMMessage)({
|
|
162
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
163
|
-
issueName: 'Use scrypt',
|
|
164
|
-
description: 'Use scrypt for password hashing',
|
|
165
|
-
severity: 'LOW',
|
|
166
|
-
fix: 'crypto.scrypt(password, salt, 64)',
|
|
167
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback',
|
|
168
|
-
}),
|
|
169
|
-
useArgon2: (0, eslint_devkit_1.formatLLMMessage)({
|
|
170
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
171
|
-
issueName: 'Use Argon2',
|
|
172
|
-
description: 'Use Argon2 for password hashing',
|
|
173
|
-
severity: 'LOW',
|
|
174
|
-
fix: 'argon2.hash(password)',
|
|
175
|
-
documentationLink: 'https://github.com/ranisalt/node-argon2',
|
|
176
|
-
}),
|
|
177
|
-
useAes256: (0, eslint_devkit_1.formatLLMMessage)({
|
|
178
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
179
|
-
issueName: 'Use AES-256-GCM',
|
|
180
|
-
description: 'Use AES-256-GCM for encryption',
|
|
181
|
-
severity: 'LOW',
|
|
182
|
-
fix: 'Use crypto.createCipheriv("aes-256-gcm", key, iv)',
|
|
183
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
|
|
184
|
-
}),
|
|
185
|
-
strategyAuto: (0, eslint_devkit_1.formatLLMMessage)({
|
|
186
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
187
|
-
issueName: 'Auto-fix Strategy',
|
|
188
|
-
description: 'Automatically suggest the best replacement',
|
|
189
|
-
severity: 'LOW',
|
|
190
|
-
fix: 'Apply automatic fix suggestion',
|
|
191
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Weak_Cryptography',
|
|
192
|
-
}),
|
|
193
|
-
strategyUpgrade: (0, eslint_devkit_1.formatLLMMessage)({
|
|
194
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
195
|
-
issueName: 'Upgrade Strategy',
|
|
196
|
-
description: 'Upgrade to a stronger algorithm',
|
|
197
|
-
severity: 'LOW',
|
|
198
|
-
fix: 'Replace weak algorithm with stronger alternative',
|
|
199
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Weak_Cryptography',
|
|
200
|
-
}),
|
|
201
|
-
strategyMigrate: (0, eslint_devkit_1.formatLLMMessage)({
|
|
202
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
203
|
-
issueName: 'Migration Strategy',
|
|
204
|
-
description: 'Plan migration to stronger cryptography',
|
|
205
|
-
severity: 'LOW',
|
|
206
|
-
fix: 'Create migration plan for cryptographic upgrade',
|
|
207
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Weak_Cryptography',
|
|
208
|
-
}),
|
|
209
|
-
strategyPolicy: (0, eslint_devkit_1.formatLLMMessage)({
|
|
210
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
211
|
-
issueName: 'Policy Strategy',
|
|
212
|
-
description: 'Apply organizational security policy',
|
|
213
|
-
severity: 'LOW',
|
|
214
|
-
fix: 'crypto.createCipheriv("aes-256-gcm", key, iv)',
|
|
215
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
|
|
216
|
-
}),
|
|
217
|
-
},
|
|
218
|
-
schema: [
|
|
219
|
-
{
|
|
220
|
-
type: 'object',
|
|
221
|
-
properties: {
|
|
222
|
-
allowInTests: {
|
|
223
|
-
type: 'boolean',
|
|
224
|
-
default: false,
|
|
225
|
-
description: 'Allow weak crypto in test files',
|
|
226
|
-
},
|
|
227
|
-
additionalWeakAlgorithms: {
|
|
228
|
-
type: 'array',
|
|
229
|
-
items: { type: 'string' },
|
|
230
|
-
default: [],
|
|
231
|
-
description: 'Additional weak algorithms to detect',
|
|
232
|
-
},
|
|
233
|
-
trustedLibraries: {
|
|
234
|
-
type: 'array',
|
|
235
|
-
items: { type: 'string' },
|
|
236
|
-
default: ['crypto', 'crypto-js'],
|
|
237
|
-
description: 'Trusted crypto libraries',
|
|
238
|
-
},
|
|
239
|
-
},
|
|
240
|
-
additionalProperties: false,
|
|
241
|
-
},
|
|
242
|
-
],
|
|
243
|
-
},
|
|
244
|
-
defaultOptions: [
|
|
245
|
-
{
|
|
246
|
-
allowInTests: false,
|
|
247
|
-
additionalWeakAlgorithms: [],
|
|
248
|
-
trustedLibraries: ['crypto', 'crypto-js'],
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
create(context, [options = {}]) {
|
|
252
|
-
const { allowInTests = false, additionalWeakAlgorithms = [], trustedLibraries = ['crypto', 'crypto-js'], } = options;
|
|
253
|
-
const filename = context.getFilename();
|
|
254
|
-
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
255
|
-
/**
|
|
256
|
-
* Check if a call expression uses weak crypto
|
|
257
|
-
*/
|
|
258
|
-
function checkCallExpression(node) {
|
|
259
|
-
if (isTestFile) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
// Check for crypto.createHash, crypto.createCipher, etc.
|
|
263
|
-
if (node.callee.type === 'MemberExpression') {
|
|
264
|
-
// Check if it's a crypto method call (e.g., crypto.createHash, crypto.createCipher)
|
|
265
|
-
if (node.callee.object.type === 'Identifier' &&
|
|
266
|
-
node.callee.property.type === 'Identifier') {
|
|
267
|
-
const objectName = node.callee.object.name;
|
|
268
|
-
const methodName = node.callee.property.name;
|
|
269
|
-
// Check if it's a crypto method from a trusted library
|
|
270
|
-
const isCryptoMethod = (methodName === 'createHash' ||
|
|
271
|
-
methodName === 'createCipher' ||
|
|
272
|
-
methodName === 'createCipheriv') &&
|
|
273
|
-
(trustedLibraries.includes(objectName) || objectName === 'crypto');
|
|
274
|
-
if (isCryptoMethod) {
|
|
275
|
-
// Check arguments for weak algorithms
|
|
276
|
-
for (const arg of node.arguments) {
|
|
277
|
-
if (arg.type === 'Literal' && typeof arg.value === 'string') {
|
|
278
|
-
const weakPattern = containsWeakCrypto(arg.value, additionalWeakAlgorithms);
|
|
279
|
-
if (weakPattern) {
|
|
280
|
-
const safeAlternative = weakPattern.alternatives[0];
|
|
281
|
-
const refactoringSteps = generateRefactoringSteps(weakPattern, 'data');
|
|
282
|
-
context.report({
|
|
283
|
-
node: arg,
|
|
284
|
-
messageId: 'weakCrypto',
|
|
285
|
-
data: {
|
|
286
|
-
algorithm: weakPattern.name,
|
|
287
|
-
safeAlternative: `Use ${safeAlternative}: ${weakPattern.example.good}`,
|
|
288
|
-
},
|
|
289
|
-
suggest: refactoringSteps.map(step => ({
|
|
290
|
-
messageId: step.messageId,
|
|
291
|
-
fix: (fixer) => {
|
|
292
|
-
// Replace the weak algorithm with a safe one
|
|
293
|
-
if (weakPattern.category === 'hash') {
|
|
294
|
-
return fixer.replaceText(arg, `"sha256"`);
|
|
295
|
-
}
|
|
296
|
-
else if (weakPattern.category === 'encryption') {
|
|
297
|
-
return fixer.replaceText(arg, `"aes-256-gcm"`);
|
|
298
|
-
}
|
|
299
|
-
return null;
|
|
300
|
-
},
|
|
301
|
-
})),
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
// Check for standalone crypto function calls (e.g., createHash, createCipher)
|
|
310
|
-
if (node.callee.type === 'Identifier') {
|
|
311
|
-
const calleeName = node.callee.name;
|
|
312
|
-
// Check for common crypto library patterns
|
|
313
|
-
if (calleeName === 'createHash' || calleeName === 'createCipher' || calleeName === 'createCipheriv') {
|
|
314
|
-
for (const arg of node.arguments) {
|
|
315
|
-
if (arg.type === 'Literal' && typeof arg.value === 'string') {
|
|
316
|
-
const weakPattern = containsWeakCrypto(arg.value, additionalWeakAlgorithms);
|
|
317
|
-
if (weakPattern) {
|
|
318
|
-
const safeAlternative = weakPattern.alternatives[0];
|
|
319
|
-
context.report({
|
|
320
|
-
node: arg,
|
|
321
|
-
messageId: 'weakCrypto',
|
|
322
|
-
data: {
|
|
323
|
-
algorithm: weakPattern.name,
|
|
324
|
-
safeAlternative: `Use ${safeAlternative}: ${weakPattern.example.good}`,
|
|
325
|
-
},
|
|
326
|
-
suggest: [
|
|
327
|
-
{
|
|
328
|
-
messageId: weakPattern.category === 'hash' ? 'useSha256' : 'useAes256',
|
|
329
|
-
fix: (fixer) => {
|
|
330
|
-
if (weakPattern.category === 'hash') {
|
|
331
|
-
return fixer.replaceText(arg, `"sha256"`);
|
|
332
|
-
}
|
|
333
|
-
else if (weakPattern.category === 'encryption') {
|
|
334
|
-
return fixer.replaceText(arg, `"aes-256-gcm"`);
|
|
335
|
-
}
|
|
336
|
-
return null;
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
],
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return {
|
|
348
|
-
CallExpression: checkCallExpression,
|
|
349
|
-
};
|
|
350
|
-
},
|
|
351
|
-
});
|