eslint-plugin-node-security 4.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/CHANGELOG.md +83 -0
- package/README.md +50 -0
- package/package.json +79 -0
- package/src/index.d.ts +10 -0
- package/src/index.js +118 -0
- package/src/index.js.map +1 -0
- package/src/rules/detect-child-process/index.d.ts +30 -0
- package/src/rules/detect-child-process/index.js +535 -0
- package/src/rules/detect-child-process/index.js.map +1 -0
- package/src/rules/detect-eval-with-expression/index.d.ts +28 -0
- package/src/rules/detect-eval-with-expression/index.js +398 -0
- package/src/rules/detect-eval-with-expression/index.js.map +1 -0
- package/src/rules/detect-non-literal-fs-filename/index.d.ts +26 -0
- package/src/rules/detect-non-literal-fs-filename/index.js +460 -0
- package/src/rules/detect-non-literal-fs-filename/index.js.map +1 -0
- package/src/rules/detect-suspicious-dependencies/index.d.ts +12 -0
- package/src/rules/detect-suspicious-dependencies/index.js +77 -0
- package/src/rules/detect-suspicious-dependencies/index.js.map +1 -0
- package/src/rules/lock-file/index.d.ts +13 -0
- package/src/rules/lock-file/index.js +94 -0
- package/src/rules/lock-file/index.js.map +1 -0
- package/src/rules/no-arbitrary-file-access/index.d.ts +12 -0
- package/src/rules/no-arbitrary-file-access/index.js +201 -0
- package/src/rules/no-arbitrary-file-access/index.js.map +1 -0
- package/src/rules/no-buffer-overread/index.d.ts +39 -0
- package/src/rules/no-buffer-overread/index.js +612 -0
- package/src/rules/no-buffer-overread/index.js.map +1 -0
- package/src/rules/no-cryptojs/index.d.ts +24 -0
- package/src/rules/no-cryptojs/index.js +104 -0
- package/src/rules/no-cryptojs/index.js.map +1 -0
- package/src/rules/no-cryptojs-weak-random/index.d.ts +24 -0
- package/src/rules/no-cryptojs-weak-random/index.js +112 -0
- package/src/rules/no-cryptojs-weak-random/index.js.map +1 -0
- package/src/rules/no-data-in-temp-storage/index.d.ts +14 -0
- package/src/rules/no-data-in-temp-storage/index.js +99 -0
- package/src/rules/no-data-in-temp-storage/index.js.map +1 -0
- package/src/rules/no-deprecated-cipher-method/index.d.ts +23 -0
- package/src/rules/no-deprecated-cipher-method/index.js +118 -0
- package/src/rules/no-deprecated-cipher-method/index.js.map +1 -0
- package/src/rules/no-dynamic-dependency-loading/index.d.ts +12 -0
- package/src/rules/no-dynamic-dependency-loading/index.js +55 -0
- package/src/rules/no-dynamic-dependency-loading/index.js.map +1 -0
- package/src/rules/no-dynamic-require/index.d.ts +21 -0
- package/src/rules/no-dynamic-require/index.js +122 -0
- package/src/rules/no-dynamic-require/index.js.map +1 -0
- package/src/rules/no-ecb-mode/index.d.ts +23 -0
- package/src/rules/no-ecb-mode/index.js +113 -0
- package/src/rules/no-ecb-mode/index.js.map +1 -0
- package/src/rules/no-insecure-key-derivation/index.d.ts +24 -0
- package/src/rules/no-insecure-key-derivation/index.js +116 -0
- package/src/rules/no-insecure-key-derivation/index.js.map +1 -0
- package/src/rules/no-insecure-rsa-padding/index.d.ts +24 -0
- package/src/rules/no-insecure-rsa-padding/index.js +110 -0
- package/src/rules/no-insecure-rsa-padding/index.js.map +1 -0
- package/src/rules/no-pii-in-logs/index.d.ts +12 -0
- package/src/rules/no-pii-in-logs/index.js +74 -0
- package/src/rules/no-pii-in-logs/index.js.map +1 -0
- package/src/rules/no-self-signed-certs/index.d.ts +23 -0
- package/src/rules/no-self-signed-certs/index.js +116 -0
- package/src/rules/no-self-signed-certs/index.js.map +1 -0
- package/src/rules/no-sha1-hash/index.d.ts +24 -0
- package/src/rules/no-sha1-hash/index.js +128 -0
- package/src/rules/no-sha1-hash/index.js.map +1 -0
- package/src/rules/no-static-iv/index.d.ts +23 -0
- package/src/rules/no-static-iv/index.js +147 -0
- package/src/rules/no-static-iv/index.js.map +1 -0
- package/src/rules/no-timing-unsafe-compare/index.d.ts +23 -0
- package/src/rules/no-timing-unsafe-compare/index.js +114 -0
- package/src/rules/no-timing-unsafe-compare/index.js.map +1 -0
- package/src/rules/no-toctou-vulnerability/index.d.ts +26 -0
- package/src/rules/no-toctou-vulnerability/index.js +214 -0
- package/src/rules/no-toctou-vulnerability/index.js.map +1 -0
- package/src/rules/no-unsafe-dynamic-require/index.d.ts +19 -0
- package/src/rules/no-unsafe-dynamic-require/index.js +112 -0
- package/src/rules/no-unsafe-dynamic-require/index.js.map +1 -0
- package/src/rules/no-weak-cipher-algorithm/index.d.ts +25 -0
- package/src/rules/no-weak-cipher-algorithm/index.js +190 -0
- package/src/rules/no-weak-cipher-algorithm/index.js.map +1 -0
- package/src/rules/no-weak-hash-algorithm/index.d.ts +25 -0
- package/src/rules/no-weak-hash-algorithm/index.js +218 -0
- package/src/rules/no-weak-hash-algorithm/index.js.map +1 -0
- package/src/rules/no-zip-slip/index.d.ts +35 -0
- package/src/rules/no-zip-slip/index.js +451 -0
- package/src/rules/no-zip-slip/index.js.map +1 -0
- package/src/rules/prefer-native-crypto/index.d.ts +23 -0
- package/src/rules/prefer-native-crypto/index.js +124 -0
- package/src/rules/prefer-native-crypto/index.js.map +1 -0
- package/src/rules/require-dependency-integrity/index.d.ts +12 -0
- package/src/rules/require-dependency-integrity/index.js +70 -0
- package/src/rules/require-dependency-integrity/index.js.map +1 -0
- package/src/rules/require-secure-credential-storage/index.d.ts +12 -0
- package/src/rules/require-secure-credential-storage/index.js +54 -0
- package/src/rules/require-secure-credential-storage/index.js.map +1 -0
- package/src/rules/require-secure-deletion/index.d.ts +12 -0
- package/src/rules/require-secure-deletion/index.js +46 -0
- package/src/rules/require-secure-deletion/index.js.map +1 -0
- package/src/rules/require-storage-encryption/index.d.ts +12 -0
- package/src/rules/require-storage-encryption/index.js +54 -0
- package/src/rules/require-storage-encryption/index.js.map +1 -0
- package/src/types/index.d.ts +24 -0
- package/src/types/index.js +8 -0
- package/src/types/index.js.map +1 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
+
* MIT license that can be found in the LICENSE file.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.noWeakHashAlgorithm = void 0;
|
|
9
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
+
const WEAK_HASH_PATTERNS = [
|
|
11
|
+
{
|
|
12
|
+
pattern: /\bmd5\b/i,
|
|
13
|
+
name: 'MD5',
|
|
14
|
+
alternatives: ['SHA-256', 'SHA-512', 'SHA-3'],
|
|
15
|
+
replacement: 'sha256',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
pattern: /\bmd4\b/i,
|
|
19
|
+
name: 'MD4',
|
|
20
|
+
alternatives: ['SHA-256', 'SHA-512', 'SHA-3'],
|
|
21
|
+
replacement: 'sha256',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
pattern: /\bsha1\b/i,
|
|
25
|
+
name: 'SHA-1',
|
|
26
|
+
alternatives: ['SHA-256', 'SHA-512', 'SHA-3'],
|
|
27
|
+
replacement: 'sha256',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
pattern: /\bripemd\b/i,
|
|
31
|
+
name: 'RIPEMD',
|
|
32
|
+
alternatives: ['SHA-256', 'SHA-512'],
|
|
33
|
+
replacement: 'sha256',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Check if a string contains a weak hash algorithm
|
|
38
|
+
*/
|
|
39
|
+
function findWeakHash(value, additionalPatterns) {
|
|
40
|
+
// Check standard patterns
|
|
41
|
+
for (const pattern of WEAK_HASH_PATTERNS) {
|
|
42
|
+
if (pattern.pattern.test(value)) {
|
|
43
|
+
return pattern;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Check additional patterns
|
|
47
|
+
for (const additionalPattern of additionalPatterns) {
|
|
48
|
+
const regex = new RegExp(`\\b${additionalPattern}\\b`, 'i');
|
|
49
|
+
if (regex.test(value)) {
|
|
50
|
+
return {
|
|
51
|
+
pattern: regex,
|
|
52
|
+
name: additionalPattern.toUpperCase(),
|
|
53
|
+
alternatives: ['SHA-256', 'SHA-512'],
|
|
54
|
+
replacement: 'sha256',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
exports.noWeakHashAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
61
|
+
name: 'no-weak-hash-algorithm',
|
|
62
|
+
meta: {
|
|
63
|
+
type: 'problem',
|
|
64
|
+
docs: {
|
|
65
|
+
description: 'Disallow weak hash algorithms (MD5, SHA1, MD4)',
|
|
66
|
+
},
|
|
67
|
+
hasSuggestions: true,
|
|
68
|
+
messages: {
|
|
69
|
+
weakHashAlgorithm: (0, eslint_devkit_1.formatLLMMessage)({
|
|
70
|
+
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
71
|
+
issueName: 'Weak hash algorithm',
|
|
72
|
+
cwe: 'CWE-327',
|
|
73
|
+
description: 'Use of weak hash algorithm: {{algorithm}}. {{algorithm}} is cryptographically broken and unsuitable for security purposes.',
|
|
74
|
+
severity: 'CRITICAL',
|
|
75
|
+
fix: 'Replace with {{replacement}}: crypto.createHash("{{replacement}}").update(data)',
|
|
76
|
+
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Weak_Cryptography',
|
|
77
|
+
}),
|
|
78
|
+
useSha256: (0, eslint_devkit_1.formatLLMMessage)({
|
|
79
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
80
|
+
issueName: 'Use SHA-256',
|
|
81
|
+
description: 'Replace with SHA-256 for secure hashing',
|
|
82
|
+
severity: 'LOW',
|
|
83
|
+
fix: 'crypto.createHash("sha256").update(data)',
|
|
84
|
+
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatehashmethod-options',
|
|
85
|
+
}),
|
|
86
|
+
useSha512: (0, eslint_devkit_1.formatLLMMessage)({
|
|
87
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
88
|
+
issueName: 'Use SHA-512',
|
|
89
|
+
description: 'Replace with SHA-512 for stronger hashing',
|
|
90
|
+
severity: 'LOW',
|
|
91
|
+
fix: 'crypto.createHash("sha512").update(data)',
|
|
92
|
+
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatehashmethod-options',
|
|
93
|
+
}),
|
|
94
|
+
useSha3: (0, eslint_devkit_1.formatLLMMessage)({
|
|
95
|
+
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
96
|
+
issueName: 'Use SHA-3',
|
|
97
|
+
description: 'Replace with SHA-3 for latest standard',
|
|
98
|
+
severity: 'LOW',
|
|
99
|
+
fix: 'crypto.createHash("sha3-256").update(data)',
|
|
100
|
+
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatehashmethod-options',
|
|
101
|
+
}),
|
|
102
|
+
},
|
|
103
|
+
schema: [
|
|
104
|
+
{
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
additionalWeakAlgorithms: {
|
|
108
|
+
type: 'array',
|
|
109
|
+
items: { type: 'string' },
|
|
110
|
+
default: [],
|
|
111
|
+
description: 'Additional weak algorithms to detect',
|
|
112
|
+
},
|
|
113
|
+
allowInTests: {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
default: false,
|
|
116
|
+
description: 'Allow weak hashes in test files',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
defaultOptions: [
|
|
124
|
+
{
|
|
125
|
+
additionalWeakAlgorithms: [],
|
|
126
|
+
allowInTests: false,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
create(context, [options = {}]) {
|
|
130
|
+
const { additionalWeakAlgorithms = [], allowInTests = false, } = options;
|
|
131
|
+
const filename = context.filename;
|
|
132
|
+
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
133
|
+
/**
|
|
134
|
+
* Check if a call expression uses a weak hash
|
|
135
|
+
*/
|
|
136
|
+
function checkCallExpression(node) {
|
|
137
|
+
if (isTestFile)
|
|
138
|
+
return;
|
|
139
|
+
// Check for crypto.createHash() pattern
|
|
140
|
+
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
141
|
+
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
142
|
+
node.callee.property.name === 'createHash') {
|
|
143
|
+
checkHashArgument(node);
|
|
144
|
+
}
|
|
145
|
+
// Check for standalone createHash() pattern
|
|
146
|
+
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
147
|
+
node.callee.name === 'createHash') {
|
|
148
|
+
checkHashArgument(node);
|
|
149
|
+
}
|
|
150
|
+
// Check for crypto-hash package: sha1(), md5()
|
|
151
|
+
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
152
|
+
const funcName = node.callee.name.toLowerCase();
|
|
153
|
+
if (funcName === 'sha1' || funcName === 'md5' || funcName === 'md4') {
|
|
154
|
+
const weakPattern = findWeakHash(funcName, additionalWeakAlgorithms);
|
|
155
|
+
if (weakPattern) {
|
|
156
|
+
context.report({
|
|
157
|
+
node,
|
|
158
|
+
messageId: 'weakHashAlgorithm',
|
|
159
|
+
data: {
|
|
160
|
+
algorithm: weakPattern.name,
|
|
161
|
+
replacement: weakPattern.replacement,
|
|
162
|
+
},
|
|
163
|
+
suggest: [
|
|
164
|
+
{
|
|
165
|
+
messageId: 'useSha256',
|
|
166
|
+
fix: (fixer) => {
|
|
167
|
+
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
168
|
+
return fixer.replaceText(node.callee, 'sha256');
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Check the algorithm argument passed to createHash
|
|
181
|
+
*/
|
|
182
|
+
function checkHashArgument(node) {
|
|
183
|
+
for (const arg of node.arguments) {
|
|
184
|
+
if (arg.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof arg.value === 'string') {
|
|
185
|
+
const weakPattern = findWeakHash(arg.value, additionalWeakAlgorithms);
|
|
186
|
+
if (weakPattern) {
|
|
187
|
+
context.report({
|
|
188
|
+
node: arg,
|
|
189
|
+
messageId: 'weakHashAlgorithm',
|
|
190
|
+
data: {
|
|
191
|
+
algorithm: weakPattern.name,
|
|
192
|
+
replacement: weakPattern.replacement,
|
|
193
|
+
},
|
|
194
|
+
suggest: [
|
|
195
|
+
{
|
|
196
|
+
messageId: 'useSha256',
|
|
197
|
+
fix: (fixer) => fixer.replaceText(arg, `"sha256"`),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
messageId: 'useSha512',
|
|
201
|
+
fix: (fixer) => fixer.replaceText(arg, `"sha512"`),
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
messageId: 'useSha3',
|
|
205
|
+
fix: (fixer) => fixer.replaceText(arg, `"sha3-256"`),
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
CallExpression: checkCallExpression,
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-weak-hash-algorithm/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
3
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
4
|
+
* MIT license that can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* ESLint Rule: no-zip-slip
|
|
8
|
+
* Detects zip slip/archive extraction vulnerabilities (CWE-22)
|
|
9
|
+
*
|
|
10
|
+
* Zip slip vulnerabilities occur when extracting archives without properly
|
|
11
|
+
* validating file paths, allowing attackers to write files outside the
|
|
12
|
+
* intended extraction directory using path traversal sequences like "../".
|
|
13
|
+
*
|
|
14
|
+
* False Positive Reduction:
|
|
15
|
+
* This rule uses security utilities to reduce false positives by detecting:
|
|
16
|
+
* - Safe archive extraction patterns
|
|
17
|
+
* - Path validation functions
|
|
18
|
+
* - JSDoc annotations (@safe, @validated)
|
|
19
|
+
* - Trusted extraction libraries
|
|
20
|
+
*/
|
|
21
|
+
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
22
|
+
type MessageIds = 'zipSlipVulnerability' | 'unsafeArchiveExtraction' | 'pathTraversalInArchive' | 'unvalidatedArchivePath' | 'dangerousArchiveDestination' | 'useSafeArchiveExtraction' | 'validateArchivePaths' | 'sanitizeArchiveNames' | 'strategyPathValidation' | 'strategySafeLibraries' | 'strategySandboxing';
|
|
23
|
+
export interface Options {
|
|
24
|
+
/** Archive extraction functions to check */
|
|
25
|
+
archiveFunctions?: string[];
|
|
26
|
+
/** Functions that safely validate archive paths */
|
|
27
|
+
pathValidationFunctions?: string[];
|
|
28
|
+
/** Safe archive extraction libraries */
|
|
29
|
+
safeLibraries?: string[];
|
|
30
|
+
}
|
|
31
|
+
type RuleOptions = [Options?];
|
|
32
|
+
export declare const noZipSlip: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
|
|
33
|
+
name: string;
|
|
34
|
+
};
|
|
35
|
+
export {};
|