eslint-plugin-node-security 4.5.0 → 4.7.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/README.md +2 -0
- package/package.json +5 -8
- package/src/index.d.ts +17 -10
- package/src/index.js +8 -31
- package/src/oxlint.d.ts +17 -20
- package/src/oxlint.js +0 -19
- package/src/rules/detect-child-process/index.js +0 -107
- package/src/rules/detect-eval-with-expression/index.js +2 -48
- package/src/rules/detect-non-literal-fs-filename/index.js +0 -82
- package/src/rules/detect-suspicious-dependencies/index.js +0 -12
- package/src/rules/lock-file/index.js +0 -18
- package/src/rules/no-arbitrary-file-access/index.js +0 -52
- package/src/rules/no-buffer-overread/index.js +3 -96
- package/src/rules/no-cryptojs/index.js +2 -10
- package/src/rules/no-cryptojs-weak-random/index.js +1 -13
- package/src/rules/no-data-in-temp-storage/index.js +0 -12
- package/src/rules/no-deprecated-buffer/index.js +0 -15
- package/src/rules/no-deprecated-cipher-method/index.js +0 -9
- package/src/rules/no-dynamic-algorithm-selection/index.js +0 -13
- package/src/rules/no-dynamic-command-string/index.js +201 -0
- package/src/rules/no-dynamic-dependency-loading/index.js +0 -13
- package/src/rules/no-dynamic-require/index.js +0 -10
- package/src/rules/no-ecb-mode/index.js +0 -7
- package/src/rules/no-insecure-key-derivation/index.js +0 -10
- package/src/rules/no-insecure-rsa-padding/index.js +0 -9
- package/src/rules/no-math-random-crypto/index.js +1 -17
- package/src/rules/no-self-signed-certs/index.js +1 -9
- package/src/rules/no-sha1-hash/index.js +0 -9
- package/src/rules/no-shell-injection/index.js +0 -20
- package/src/rules/no-ssrf/index.js +5 -79
- package/src/rules/no-static-iv/index.js +2 -21
- package/src/rules/no-timing-unsafe-compare/index.js +1 -11
- package/src/rules/no-toctou-vulnerability/index.js +0 -22
- package/src/rules/no-unsafe-buffer-alloc/index.js +87 -0
- package/src/rules/no-unsafe-dynamic-require/index.js +0 -22
- package/src/rules/no-weak-cipher-algorithm/index.js +0 -19
- package/src/rules/no-weak-hash-algorithm/index.js +0 -22
- package/src/rules/no-zip-slip/index.js +3 -81
- package/src/rules/prefer-native-crypto/index.js +4 -11
- package/src/rules/require-dependency-integrity/index.js +0 -11
- package/src/rules/require-secure-credential-storage/index.js +0 -12
- package/src/rules/require-secure-deletion/index.js +0 -29
- package/src/rules/require-storage-encryption/index.js +0 -12
- package/src/types/index.js +0 -6
- package/CHANGELOG.md +0 -384
- package/src/index.js.map +0 -1
- package/src/oxlint.js.map +0 -1
- package/src/rules/detect-child-process/index.d.ts +0 -52
- package/src/rules/detect-child-process/index.js.map +0 -1
- package/src/rules/detect-eval-with-expression/index.d.ts +0 -46
- package/src/rules/detect-eval-with-expression/index.js.map +0 -1
- package/src/rules/detect-non-literal-fs-filename/index.d.ts +0 -52
- package/src/rules/detect-non-literal-fs-filename/index.js.map +0 -1
- package/src/rules/detect-suspicious-dependencies/index.d.ts +0 -12
- package/src/rules/detect-suspicious-dependencies/index.js.map +0 -1
- package/src/rules/lock-file/index.d.ts +0 -13
- package/src/rules/lock-file/index.js.map +0 -1
- package/src/rules/no-arbitrary-file-access/index.d.ts +0 -12
- package/src/rules/no-arbitrary-file-access/index.js.map +0 -1
- package/src/rules/no-buffer-overread/index.d.ts +0 -39
- package/src/rules/no-buffer-overread/index.js.map +0 -1
- package/src/rules/no-cryptojs/index.d.ts +0 -24
- package/src/rules/no-cryptojs/index.js.map +0 -1
- package/src/rules/no-cryptojs-weak-random/index.d.ts +0 -24
- package/src/rules/no-cryptojs-weak-random/index.js.map +0 -1
- package/src/rules/no-data-in-temp-storage/index.d.ts +0 -14
- package/src/rules/no-data-in-temp-storage/index.js.map +0 -1
- package/src/rules/no-deprecated-buffer/index.d.ts +0 -23
- package/src/rules/no-deprecated-buffer/index.js.map +0 -1
- package/src/rules/no-deprecated-cipher-method/index.d.ts +0 -23
- package/src/rules/no-deprecated-cipher-method/index.js.map +0 -1
- package/src/rules/no-dynamic-algorithm-selection/index.d.ts +0 -26
- package/src/rules/no-dynamic-algorithm-selection/index.js.map +0 -1
- package/src/rules/no-dynamic-dependency-loading/index.d.ts +0 -12
- package/src/rules/no-dynamic-dependency-loading/index.js.map +0 -1
- package/src/rules/no-dynamic-require/index.d.ts +0 -21
- package/src/rules/no-dynamic-require/index.js.map +0 -1
- package/src/rules/no-ecb-mode/index.d.ts +0 -23
- package/src/rules/no-ecb-mode/index.js.map +0 -1
- package/src/rules/no-insecure-key-derivation/index.d.ts +0 -24
- package/src/rules/no-insecure-key-derivation/index.js.map +0 -1
- package/src/rules/no-insecure-rsa-padding/index.d.ts +0 -24
- package/src/rules/no-insecure-rsa-padding/index.js.map +0 -1
- package/src/rules/no-math-random-crypto/index.d.ts +0 -26
- package/src/rules/no-math-random-crypto/index.js.map +0 -1
- package/src/rules/no-self-signed-certs/index.d.ts +0 -23
- package/src/rules/no-self-signed-certs/index.js.map +0 -1
- package/src/rules/no-sha1-hash/index.d.ts +0 -24
- package/src/rules/no-sha1-hash/index.js.map +0 -1
- package/src/rules/no-shell-injection/index.d.ts +0 -20
- package/src/rules/no-shell-injection/index.js.map +0 -1
- package/src/rules/no-ssrf/index.d.ts +0 -25
- package/src/rules/no-ssrf/index.js.map +0 -1
- package/src/rules/no-static-iv/index.d.ts +0 -23
- package/src/rules/no-static-iv/index.js.map +0 -1
- package/src/rules/no-timing-unsafe-compare/index.d.ts +0 -23
- package/src/rules/no-timing-unsafe-compare/index.js.map +0 -1
- package/src/rules/no-toctou-vulnerability/index.d.ts +0 -26
- package/src/rules/no-toctou-vulnerability/index.js.map +0 -1
- package/src/rules/no-unsafe-dynamic-require/index.d.ts +0 -19
- package/src/rules/no-unsafe-dynamic-require/index.js.map +0 -1
- package/src/rules/no-weak-cipher-algorithm/index.d.ts +0 -25
- package/src/rules/no-weak-cipher-algorithm/index.js.map +0 -1
- package/src/rules/no-weak-hash-algorithm/index.d.ts +0 -25
- package/src/rules/no-weak-hash-algorithm/index.js.map +0 -1
- package/src/rules/no-zip-slip/index.d.ts +0 -35
- package/src/rules/no-zip-slip/index.js.map +0 -1
- package/src/rules/prefer-native-crypto/index.d.ts +0 -23
- package/src/rules/prefer-native-crypto/index.js.map +0 -1
- package/src/rules/require-dependency-integrity/index.d.ts +0 -12
- package/src/rules/require-dependency-integrity/index.js.map +0 -1
- package/src/rules/require-secure-credential-storage/index.d.ts +0 -12
- package/src/rules/require-secure-credential-storage/index.js.map +0 -1
- package/src/rules/require-secure-deletion/index.d.ts +0 -17
- package/src/rules/require-secure-deletion/index.js.map +0 -1
- package/src/rules/require-storage-encryption/index.d.ts +0 -12
- package/src/rules/require-storage-encryption/index.js.map +0 -1
- package/src/types/index.js.map +0 -1
|
@@ -1,57 +1,34 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noSsrf = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
// HTTP client functions that make outbound requests
|
|
11
5
|
const HTTP_CLIENT_FUNCTIONS = new Set([
|
|
12
|
-
'fetch',
|
|
13
|
-
'got',
|
|
14
|
-
'nodeFetch',
|
|
15
|
-
'undici',
|
|
6
|
+
'fetch',
|
|
7
|
+
'got',
|
|
8
|
+
'nodeFetch',
|
|
9
|
+
'undici',
|
|
16
10
|
]);
|
|
17
|
-
// HTTP client method calls (e.g., axios.get, http.request)
|
|
18
11
|
const HTTP_CLIENT_METHODS = new Set([
|
|
19
12
|
'get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'request',
|
|
20
13
|
]);
|
|
21
|
-
// Object names that are HTTP client libraries
|
|
22
14
|
const HTTP_CLIENT_OBJECTS = new Set([
|
|
23
|
-
'axios', 'got', 'superagent', 'request', 'http', 'https', 'undici',
|
|
15
|
+
'axios', 'got', 'superagent', 'request', 'http', 'https', 'undici', 'needle',
|
|
24
16
|
]);
|
|
25
|
-
// Function names that indicate URL validation
|
|
26
17
|
const VALIDATION_FUNCTION_NAMES = new Set([
|
|
27
18
|
'validateUrl', 'validateURL', 'isValidUrl', 'isSafeUrl', 'isAllowed',
|
|
28
19
|
'isValidURL', 'checkUrl', 'checkURL', 'sanitizeUrl', 'sanitizeURL',
|
|
29
20
|
]);
|
|
30
|
-
// Substrings in identifier names that suggest user input
|
|
31
21
|
const USER_INPUT_SUBSTRINGS = [
|
|
32
22
|
'url', 'endpoint', 'uri', 'href', 'link',
|
|
33
23
|
'target', 'dest', 'source', 'host',
|
|
34
24
|
'user', 'input', 'param',
|
|
35
25
|
];
|
|
36
|
-
/**
|
|
37
|
-
* Check if a function parameter name suggests user input
|
|
38
|
-
*/
|
|
39
26
|
function isUserInputParamName(name) {
|
|
40
27
|
const lower = name.toLowerCase();
|
|
41
28
|
return USER_INPUT_SUBSTRINGS.some(sub => lower.includes(sub));
|
|
42
29
|
}
|
|
43
|
-
// Object roots whose members carry attacker-controlled data in the common
|
|
44
|
-
// server frameworks: Express `req`/`request`, Koa `ctx`, Lambda `event`.
|
|
45
30
|
const REQUEST_ROOT_NAMES = new Set(['req', 'request', 'ctx', 'event']);
|
|
46
|
-
// Keys of a Node `http.request(options)` object that actually name a URL.
|
|
47
|
-
// `host`/`hostname`/`path`/`port` are deliberately absent: a helper that
|
|
48
|
-
// parameterises them is ordinary internal plumbing, not evidence of user flow.
|
|
49
31
|
const URL_OPTION_KEYS = new Set(['url', 'href', 'uri']);
|
|
50
|
-
/**
|
|
51
|
-
* True when the expression reads off a request object — `req.query.url`,
|
|
52
|
-
* `ctx.request.body.target`, `event.queryStringParameters.u`. Everything
|
|
53
|
-
* hanging off a request is untrusted, so the root name is the whole test.
|
|
54
|
-
*/
|
|
55
32
|
function isRequestSourced(node) {
|
|
56
33
|
let current = node;
|
|
57
34
|
while (current.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
@@ -61,26 +38,6 @@ function isRequestSourced(node) {
|
|
|
61
38
|
current.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
62
39
|
REQUEST_ROOT_NAMES.has(current.name.toLowerCase()));
|
|
63
40
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Does the URL argument carry untrusted data into the request?
|
|
66
|
-
*
|
|
67
|
-
* The rule reports on evidence of flow, never on the mere presence of a
|
|
68
|
-
* dynamic argument. Three shapes qualify:
|
|
69
|
-
*
|
|
70
|
-
* 1. The whole argument is a user-input-named identifier — `fetch(userUrl)`.
|
|
71
|
-
* This is the rule's documented naming heuristic: a bare identifier in
|
|
72
|
-
* URL position *is* the URL.
|
|
73
|
-
* 2. Any part of the expression reads from a request object —
|
|
74
|
-
* `fetch(req.query.url)`, `https.request({ host: req.query.h })`.
|
|
75
|
-
* 3. A template literal URL interpolates either of the above —
|
|
76
|
-
* `fetch(\`https://\${userHost}/x\`)`.
|
|
77
|
-
*
|
|
78
|
-
* Everything else is not evidence. In particular an options object whose
|
|
79
|
-
* fields are plain locals — `https.request({ host, path, method: 'GET' })`,
|
|
80
|
-
* benchmarks/corpus/CWE-444/safe/request-default-parser.js — used to be
|
|
81
|
-
* reported unconditionally because a non-Identifier argument bypassed the
|
|
82
|
-
* name gate entirely.
|
|
83
|
-
*/
|
|
84
41
|
function carriesUntrustedUrl(node) {
|
|
85
42
|
switch (node.type) {
|
|
86
43
|
case eslint_devkit_1.AST_NODE_TYPES.Identifier:
|
|
@@ -89,15 +46,11 @@ function carriesUntrustedUrl(node) {
|
|
|
89
46
|
return isRequestSourced(node);
|
|
90
47
|
case eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral:
|
|
91
48
|
return node.expressions.some(carriesUntrustedUrl);
|
|
92
|
-
// `new URL(userUrl)` / `String(req.query.url)` — inspect the arguments.
|
|
93
49
|
case eslint_devkit_1.AST_NODE_TYPES.CallExpression:
|
|
94
50
|
case eslint_devkit_1.AST_NODE_TYPES.NewExpression:
|
|
95
51
|
return node.arguments.some(carriesUntrustedUrl);
|
|
96
|
-
// `'https://host' + userPath`
|
|
97
52
|
case eslint_devkit_1.AST_NODE_TYPES.BinaryExpression:
|
|
98
53
|
return carriesUntrustedUrl(node.left) || carriesUntrustedUrl(node.right);
|
|
99
|
-
// `http.request({ url: x, host: y })` — only URL-naming keys count by
|
|
100
|
-
// name; every other key still counts if its value is request-sourced.
|
|
101
54
|
case eslint_devkit_1.AST_NODE_TYPES.ObjectExpression:
|
|
102
55
|
return node.properties.some(property => {
|
|
103
56
|
if (property.type !== eslint_devkit_1.AST_NODE_TYPES.Property)
|
|
@@ -116,24 +69,17 @@ function carriesUntrustedUrl(node) {
|
|
|
116
69
|
return false;
|
|
117
70
|
}
|
|
118
71
|
}
|
|
119
|
-
/**
|
|
120
|
-
* AST-based check: does this node contain a validation pattern?
|
|
121
|
-
* Walks the node tree looking for known validation constructs.
|
|
122
|
-
*/
|
|
123
72
|
function nodeContainsValidation(node) {
|
|
124
|
-
// new URL(x) — URL constructor (parsing/validation)
|
|
125
73
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.NewExpression &&
|
|
126
74
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
127
75
|
node.callee.name === 'URL') {
|
|
128
76
|
return true;
|
|
129
77
|
}
|
|
130
|
-
// validateUrl(x), isValidUrl(x), etc.
|
|
131
78
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
132
79
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
133
80
|
VALIDATION_FUNCTION_NAMES.has(node.callee.name)) {
|
|
134
81
|
return true;
|
|
135
82
|
}
|
|
136
|
-
// arr.includes(x), set.has(x), x.startsWith('...'), regex.test(x)
|
|
137
83
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
138
84
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
139
85
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
@@ -142,7 +88,6 @@ function nodeContainsValidation(node) {
|
|
|
142
88
|
return true;
|
|
143
89
|
}
|
|
144
90
|
}
|
|
145
|
-
// hostname === '...' or host === '...'
|
|
146
91
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.BinaryExpression &&
|
|
147
92
|
(node.operator === '===' || node.operator === '==') &&
|
|
148
93
|
((node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
@@ -153,13 +98,10 @@ function nodeContainsValidation(node) {
|
|
|
153
98
|
(node.right.property.name === 'hostname' || node.right.property.name === 'host')))) {
|
|
154
99
|
return true;
|
|
155
100
|
}
|
|
156
|
-
// throw new Error(...) — guard clause
|
|
157
101
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement) {
|
|
158
102
|
return true;
|
|
159
103
|
}
|
|
160
|
-
// Keys to skip: non-child properties that cause circular refs or aren't AST children
|
|
161
104
|
const SKIP_KEYS = new Set(['parent', 'range', 'loc', 'tokens', 'comments', 'start', 'end']);
|
|
162
|
-
// Recurse into child nodes
|
|
163
105
|
for (const key of Object.keys(node)) {
|
|
164
106
|
if (SKIP_KEYS.has(key))
|
|
165
107
|
continue;
|
|
@@ -179,11 +121,7 @@ function nodeContainsValidation(node) {
|
|
|
179
121
|
}
|
|
180
122
|
return false;
|
|
181
123
|
}
|
|
182
|
-
/**
|
|
183
|
-
* Check if there is URL validation before the HTTP call using AST walking
|
|
184
|
-
*/
|
|
185
124
|
function hasValidationBefore(node) {
|
|
186
|
-
// Walk up to find the containing block
|
|
187
125
|
let current = node.parent;
|
|
188
126
|
while (current) {
|
|
189
127
|
const parent = current.parent;
|
|
@@ -192,14 +130,12 @@ function hasValidationBefore(node) {
|
|
|
192
130
|
if (parent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement || parent.type === eslint_devkit_1.AST_NODE_TYPES.Program) {
|
|
193
131
|
const body = parent.body;
|
|
194
132
|
const idx = body.indexOf(current);
|
|
195
|
-
// Check previous sibling statements for validation patterns
|
|
196
133
|
for (let i = idx - 1; i >= 0 && i >= idx - 10; i--) {
|
|
197
134
|
if (nodeContainsValidation(body[i])) {
|
|
198
135
|
return true;
|
|
199
136
|
}
|
|
200
137
|
}
|
|
201
138
|
}
|
|
202
|
-
// Check if inside an if-block where the condition contains validation
|
|
203
139
|
if (parent.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement && parent.test) {
|
|
204
140
|
if (nodeContainsValidation(parent.test)) {
|
|
205
141
|
return true;
|
|
@@ -253,12 +189,10 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
253
189
|
return {
|
|
254
190
|
CallExpression(node) {
|
|
255
191
|
let isHttpCall = false;
|
|
256
|
-
// 1. Direct function call: fetch(url), got(url)
|
|
257
192
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
258
193
|
HTTP_CLIENT_FUNCTIONS.has(node.callee.name)) {
|
|
259
194
|
isHttpCall = true;
|
|
260
195
|
}
|
|
261
|
-
// 2. Method call: axios.get(url), http.request(url)
|
|
262
196
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
263
197
|
node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
264
198
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
@@ -268,19 +202,12 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
268
202
|
}
|
|
269
203
|
if (!isHttpCall)
|
|
270
204
|
return;
|
|
271
|
-
// Check the first argument (the URL)
|
|
272
205
|
const urlArg = node.arguments[0];
|
|
273
206
|
if (!urlArg)
|
|
274
207
|
return;
|
|
275
|
-
// Static URLs — fetch('https://api.example.com'), fetch(`https://…`) —
|
|
276
|
-
// carry nothing untrusted and fall out at the evidence gate below.
|
|
277
|
-
// Check if there is URL validation before this call
|
|
278
208
|
if (hasValidationBefore(node)) {
|
|
279
209
|
return;
|
|
280
210
|
}
|
|
281
|
-
// Require evidence that untrusted data reaches the URL. Applies to
|
|
282
|
-
// every argument shape — an options object or a template literal used
|
|
283
|
-
// to bypass this gate entirely and report unconditionally.
|
|
284
211
|
if (!carriesUntrustedUrl(urlArg)) {
|
|
285
212
|
return;
|
|
286
213
|
}
|
|
@@ -292,4 +219,3 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
292
219
|
};
|
|
293
220
|
},
|
|
294
221
|
});
|
|
295
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,18 +1,10 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noStaticIv = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
/**
|
|
11
|
-
* Patterns that indicate a hardcoded IV
|
|
12
|
-
*/
|
|
13
5
|
const STATIC_IV_PATTERNS = [
|
|
14
|
-
/^[0-9a-f]+$/i,
|
|
15
|
-
/^[A-Za-z0-9+/]+=*$/,
|
|
6
|
+
/^[0-9a-f]+$/i,
|
|
7
|
+
/^[A-Za-z0-9+/]+=*$/,
|
|
16
8
|
];
|
|
17
9
|
exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
18
10
|
name: 'no-static-iv',
|
|
@@ -67,10 +59,8 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
67
59
|
const { allowInTests = false } = options;
|
|
68
60
|
const filename = context.filename;
|
|
69
61
|
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
70
|
-
// Track variables assigned from randomBytes
|
|
71
62
|
const randomIvVariables = new Set();
|
|
72
63
|
function checkVariableDeclarator(node) {
|
|
73
|
-
// Track: const iv = crypto.randomBytes(16)
|
|
74
64
|
if (node.id.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
75
65
|
node.init?.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression) {
|
|
76
66
|
const init = node.init;
|
|
@@ -88,7 +78,6 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
88
78
|
function checkCallExpression(node) {
|
|
89
79
|
if (isTestFile)
|
|
90
80
|
return;
|
|
91
|
-
// Check for createCipheriv calls
|
|
92
81
|
const isCipherivCall = (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
93
82
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
94
83
|
(node.callee.property.name === 'createCipheriv' || node.callee.property.name === 'createDecipheriv')) ||
|
|
@@ -100,14 +89,12 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
100
89
|
}
|
|
101
90
|
}
|
|
102
91
|
function checkIvArgument(ivArg) {
|
|
103
|
-
// Check for string literal IV
|
|
104
92
|
if (ivArg.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof ivArg.value === 'string') {
|
|
105
93
|
const value = ivArg.value;
|
|
106
94
|
if (STATIC_IV_PATTERNS.some(p => p.test(value)) || value.length >= 8) {
|
|
107
95
|
reportStaticIv(ivArg);
|
|
108
96
|
}
|
|
109
97
|
}
|
|
110
|
-
// Check for Buffer.from('static')
|
|
111
98
|
if (ivArg.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
112
99
|
ivArg.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
113
100
|
ivArg.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
@@ -118,7 +105,6 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
118
105
|
if (firstArg?.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof firstArg.value === 'string') {
|
|
119
106
|
reportStaticIv(ivArg);
|
|
120
107
|
}
|
|
121
|
-
// Check for new Uint8Array([...])
|
|
122
108
|
if (firstArg?.type === eslint_devkit_1.AST_NODE_TYPES.ArrayExpression) {
|
|
123
109
|
const allLiterals = firstArg.elements.every((el) => el?.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof el.value === 'number');
|
|
124
110
|
if (allLiterals) {
|
|
@@ -126,11 +112,7 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
126
112
|
}
|
|
127
113
|
}
|
|
128
114
|
}
|
|
129
|
-
// Check for variable reference that's NOT from randomBytes
|
|
130
115
|
if (ivArg.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
131
|
-
// If we've tracked this variable as coming from randomBytes, it's OK
|
|
132
|
-
// Otherwise, we can't be sure - only flag if we have evidence it's static
|
|
133
|
-
// For now, we don't report variables as we can't always determine their source
|
|
134
116
|
}
|
|
135
117
|
}
|
|
136
118
|
function reportStaticIv(node) {
|
|
@@ -145,4 +127,3 @@ exports.noStaticIv = (0, eslint_devkit_1.createRule)({
|
|
|
145
127
|
};
|
|
146
128
|
},
|
|
147
129
|
});
|
|
148
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,18 +1,11 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noTimingUnsafeCompare = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
5
|
const DEFAULT_SECRET_PATTERNS = [
|
|
11
|
-
// Common secret names (camelCase, snake_case, kebab-case)
|
|
12
6
|
'token', 'secret', 'key', 'password', 'hash', 'signature',
|
|
13
7
|
'mac', 'hmac', 'digest', 'apiKey', 'api_key', 'api-key',
|
|
14
8
|
'auth', 'credential', 'bearer', 'jwt', 'csrf', 'nonce',
|
|
15
|
-
// PII and sensitive data patterns
|
|
16
9
|
'ssn', 'social_security', 'social-security',
|
|
17
10
|
'pii', 'private_key', 'private-key', 'privateKey',
|
|
18
11
|
'access_token', 'access-token', 'accessToken',
|
|
@@ -87,12 +80,10 @@ exports.noTimingUnsafeCompare = (0, eslint_devkit_1.createRule)({
|
|
|
87
80
|
return false;
|
|
88
81
|
}
|
|
89
82
|
function checkBinaryExpression(node) {
|
|
90
|
-
// Check for === or == comparisons
|
|
91
83
|
if (node.operator !== '===' && node.operator !== '==' &&
|
|
92
84
|
node.operator !== '!==' && node.operator !== '!=') {
|
|
93
85
|
return;
|
|
94
86
|
}
|
|
95
|
-
// Check if either side looks like a secret
|
|
96
87
|
const leftIsSecret = isSecretIdentifier(node.left);
|
|
97
88
|
const rightIsSecret = isSecretIdentifier(node.right);
|
|
98
89
|
if (leftIsSecret || rightIsSecret) {
|
|
@@ -102,7 +93,7 @@ exports.noTimingUnsafeCompare = (0, eslint_devkit_1.createRule)({
|
|
|
102
93
|
suggest: [
|
|
103
94
|
{
|
|
104
95
|
messageId: 'useTimingSafeEqual',
|
|
105
|
-
fix: () => null,
|
|
96
|
+
fix: () => null,
|
|
106
97
|
},
|
|
107
98
|
],
|
|
108
99
|
});
|
|
@@ -113,4 +104,3 @@ exports.noTimingUnsafeCompare = (0, eslint_devkit_1.createRule)({
|
|
|
113
104
|
};
|
|
114
105
|
},
|
|
115
106
|
});
|
|
116
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,4 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noToctouVulnerability = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -86,11 +81,7 @@ exports.noToctouVulnerability = (0, eslint_devkit_2.createRule)({
|
|
|
86
81
|
return {};
|
|
87
82
|
}
|
|
88
83
|
const sourceCode = context.sourceCode;
|
|
89
|
-
/**
|
|
90
|
-
* Check for TOCTOU patterns
|
|
91
|
-
*/
|
|
92
84
|
function checkCallExpression(node) {
|
|
93
|
-
// 1. Identify the file operation (Use)
|
|
94
85
|
let useMethodName = '';
|
|
95
86
|
if (node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier') {
|
|
96
87
|
const objectName = node.callee.object.type === 'Identifier' ? node.callee.object.name : '';
|
|
@@ -108,22 +99,14 @@ exports.noToctouVulnerability = (0, eslint_devkit_2.createRule)({
|
|
|
108
99
|
const useArg = node.arguments[0];
|
|
109
100
|
if (!useArg)
|
|
110
101
|
return;
|
|
111
|
-
// 2. Walk up to find the condition (Check)
|
|
112
102
|
let current = node.parent;
|
|
113
103
|
while (current) {
|
|
114
104
|
if (current.type === 'IfStatement') {
|
|
115
|
-
// Extract the condition node
|
|
116
105
|
let condition = current.test;
|
|
117
|
-
// Handle negated condition: if (!exists(path)) { create(path) } -> also TOCTOU but different logic?
|
|
118
|
-
// Actually TOCTOU is usually Check(exists) -> Use(read).
|
|
119
|
-
// If (!exists) -> create is Check -> Use.
|
|
120
|
-
// But strict TOCTOU is checking state then acting.
|
|
121
|
-
// If checking for negation
|
|
122
106
|
if (condition.type === 'UnaryExpression' && condition.operator === '!') {
|
|
123
107
|
condition = condition.argument;
|
|
124
108
|
}
|
|
125
109
|
if (condition.type === 'CallExpression') {
|
|
126
|
-
// Check if it's a file check method
|
|
127
110
|
let checkMethodName = '';
|
|
128
111
|
if (condition.callee.type === 'MemberExpression' && condition.callee.property.type === 'Identifier') {
|
|
129
112
|
checkMethodName = condition.callee.property.name;
|
|
@@ -133,15 +116,12 @@ exports.noToctouVulnerability = (0, eslint_devkit_2.createRule)({
|
|
|
133
116
|
}
|
|
134
117
|
const checkMethods = ['existsSync', 'statSync', 'accessSync', 'exists', 'stat', 'access'];
|
|
135
118
|
if (checkMethods.includes(checkMethodName)) {
|
|
136
|
-
// Compare arguments
|
|
137
119
|
const checkArg = condition.arguments[0];
|
|
138
120
|
if (checkArg) {
|
|
139
|
-
// Method 1: Identifier match (same variable)
|
|
140
121
|
if (checkArg.type === 'Identifier' && useArg.type === 'Identifier' && checkArg.name === useArg.name) {
|
|
141
122
|
reportToctou(node);
|
|
142
123
|
return;
|
|
143
124
|
}
|
|
144
|
-
// Method 2: Text match (fallback)
|
|
145
125
|
const checkArgText = sourceCode.getText(checkArg).replace(/\s/g, '');
|
|
146
126
|
const useArgText = sourceCode.getText(useArg).replace(/\s/g, '');
|
|
147
127
|
if (checkArgText === useArgText) {
|
|
@@ -150,7 +130,6 @@ exports.noToctouVulnerability = (0, eslint_devkit_2.createRule)({
|
|
|
150
130
|
}
|
|
151
131
|
}
|
|
152
132
|
}
|
|
153
|
-
// Handle stats.isFile() / stats.isDirectory() pattern
|
|
154
133
|
if (condition.callee.type === 'MemberExpression' &&
|
|
155
134
|
condition.callee.property.type === 'Identifier' &&
|
|
156
135
|
['isFile', 'isDirectory'].includes(condition.callee.property.name) &&
|
|
@@ -214,4 +193,3 @@ exports.noToctouVulnerability = (0, eslint_devkit_2.createRule)({
|
|
|
214
193
|
};
|
|
215
194
|
},
|
|
216
195
|
});
|
|
217
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUnsafeBufferAlloc = void 0;
|
|
4
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
+
const UNSAFE_ALLOCATORS = new Set(['allocUnsafe', 'allocUnsafeSlow']);
|
|
6
|
+
exports.noUnsafeBufferAlloc = (0, eslint_devkit_1.createRule)({
|
|
7
|
+
name: 'no-unsafe-buffer-alloc',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'problem',
|
|
10
|
+
hasSuggestions: true,
|
|
11
|
+
docs: {
|
|
12
|
+
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-unsafe-buffer-alloc.md',
|
|
13
|
+
description: 'Disallow `Buffer.allocUnsafe()` and `Buffer.allocUnsafeSlow()`, which return uninitialized memory',
|
|
14
|
+
cwe: 'CWE-908',
|
|
15
|
+
cweJustification: 'CWE-908 (Use of Uninitialized Resource) — allocUnsafe returns a view over non-zeroed heap memory; any byte not overwritten before the buffer is read or transmitted discloses prior process memory.',
|
|
16
|
+
cvss: 7.5,
|
|
17
|
+
confidence: 'high',
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
unsafeAlloc: (0, eslint_devkit_1.formatLLMMessage)({
|
|
21
|
+
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
22
|
+
issueName: 'Uninitialized Buffer Allocation',
|
|
23
|
+
cwe: 'CWE-908',
|
|
24
|
+
cvss: 7.5,
|
|
25
|
+
description: '`Buffer.allocUnsafe(size)` returns memory that has not been zeroed. Every byte not overwritten before the buffer is read or sent leaks whatever the allocator previously stored there.',
|
|
26
|
+
severity: 'HIGH',
|
|
27
|
+
fix: 'Use `Buffer.alloc(size)` (zero-filled), or keep `allocUnsafe` only where the very next statement overwrites the whole buffer — `Buffer.allocUnsafe(size).fill(0)` is accepted by this rule.',
|
|
28
|
+
documentationLink: 'https://nodejs.org/api/buffer.html#static-method-bufferallocunsafesize',
|
|
29
|
+
}),
|
|
30
|
+
unsafeAllocSlow: (0, eslint_devkit_1.formatLLMMessage)({
|
|
31
|
+
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
32
|
+
issueName: 'Uninitialized Buffer Allocation (allocUnsafeSlow)',
|
|
33
|
+
cwe: 'CWE-908',
|
|
34
|
+
cvss: 7.5,
|
|
35
|
+
description: '`Buffer.allocUnsafeSlow(size)` allocates outside the shared pool but is equally uninitialized — the returned bytes are whatever was last in that memory.',
|
|
36
|
+
severity: 'HIGH',
|
|
37
|
+
fix: 'Use `Buffer.alloc(size)`, or append `.fill(0)` to zero the allocation at the call site.',
|
|
38
|
+
documentationLink: 'https://nodejs.org/api/buffer.html#static-method-bufferallocunsafeslowsize',
|
|
39
|
+
}),
|
|
40
|
+
useSafeAlloc: 'Replace with `Buffer.alloc()` (zero-filled).',
|
|
41
|
+
},
|
|
42
|
+
schema: [],
|
|
43
|
+
},
|
|
44
|
+
defaultOptions: [],
|
|
45
|
+
create(context) {
|
|
46
|
+
function isFilledInPlace(node) {
|
|
47
|
+
const parent = node.parent;
|
|
48
|
+
if (parent?.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression ||
|
|
49
|
+
parent.object !== node ||
|
|
50
|
+
parent.computed ||
|
|
51
|
+
parent.property.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier ||
|
|
52
|
+
parent.property.name !== 'fill') {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const grandparent = parent.parent;
|
|
56
|
+
return (grandparent?.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
57
|
+
grandparent.callee === parent);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
CallExpression(node) {
|
|
61
|
+
const callee = node.callee;
|
|
62
|
+
if (callee.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression ||
|
|
63
|
+
callee.computed ||
|
|
64
|
+
callee.object.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier ||
|
|
65
|
+
callee.object.name !== 'Buffer' ||
|
|
66
|
+
callee.property.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier ||
|
|
67
|
+
!UNSAFE_ALLOCATORS.has(callee.property.name)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (isFilledInPlace(node))
|
|
71
|
+
return;
|
|
72
|
+
context.report({
|
|
73
|
+
node,
|
|
74
|
+
messageId: callee.property.name === 'allocUnsafe'
|
|
75
|
+
? 'unsafeAlloc'
|
|
76
|
+
: 'unsafeAllocSlow',
|
|
77
|
+
suggest: [
|
|
78
|
+
{
|
|
79
|
+
messageId: 'useSafeAlloc',
|
|
80
|
+
fix: (fixer) => fixer.replaceText(callee.property, 'alloc'),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
});
|
|
@@ -1,9 +1,4 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noUnsafeDynamicRequire = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -49,14 +44,7 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
49
44
|
},
|
|
50
45
|
],
|
|
51
46
|
create(context) {
|
|
52
|
-
/**
|
|
53
|
-
* Track variables that reference require
|
|
54
|
-
* Maps variable name to the node where it was assigned
|
|
55
|
-
*/
|
|
56
47
|
const requireVariables = new Set();
|
|
57
|
-
/**
|
|
58
|
-
* Check if a node is a reference to require
|
|
59
|
-
*/
|
|
60
48
|
const isRequireReference = (node) => {
|
|
61
49
|
if (node.type === 'Identifier' && node.name === 'require') {
|
|
62
50
|
return true;
|
|
@@ -66,10 +54,6 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
66
54
|
}
|
|
67
55
|
return false;
|
|
68
56
|
};
|
|
69
|
-
/**
|
|
70
|
-
* Check if argument is dynamic (not a literal)
|
|
71
|
-
*/
|
|
72
|
-
// oxlint-disable-next-line consistent-function-scoping
|
|
73
57
|
const isDynamicArgument = (arg) => {
|
|
74
58
|
if (arg.type === 'Literal')
|
|
75
59
|
return false;
|
|
@@ -79,7 +63,6 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
79
63
|
};
|
|
80
64
|
return {
|
|
81
65
|
VariableDeclarator(node) {
|
|
82
|
-
// Track when require is assigned to a variable
|
|
83
66
|
if (node.id.type === 'Identifier' && node.init) {
|
|
84
67
|
if (node.init.type === 'Identifier' && node.init.name === 'require') {
|
|
85
68
|
requireVariables.add(node.id.name);
|
|
@@ -87,21 +70,17 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
87
70
|
}
|
|
88
71
|
},
|
|
89
72
|
CallExpression(node) {
|
|
90
|
-
// Check for require() calls (direct or via variable)
|
|
91
73
|
if (node.callee.type !== 'Identifier') {
|
|
92
74
|
return;
|
|
93
75
|
}
|
|
94
|
-
// Check if callee is require or a variable that references require
|
|
95
76
|
if (!isRequireReference(node.callee)) {
|
|
96
77
|
return;
|
|
97
78
|
}
|
|
98
|
-
// Must have at least one argument
|
|
99
79
|
if (node.arguments.length === 0)
|
|
100
80
|
return;
|
|
101
81
|
const firstArg = node.arguments[0];
|
|
102
82
|
if (firstArg.type === 'SpreadElement')
|
|
103
83
|
return;
|
|
104
|
-
// Check if dynamic
|
|
105
84
|
if (!isDynamicArgument(firstArg))
|
|
106
85
|
return;
|
|
107
86
|
context.report({
|
|
@@ -112,4 +91,3 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
112
91
|
};
|
|
113
92
|
},
|
|
114
93
|
});
|
|
115
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,4 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noWeakCipherAlgorithm = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -45,17 +40,12 @@ const WEAK_CIPHER_PATTERNS = [
|
|
|
45
40
|
replacement: 'aes-256-gcm',
|
|
46
41
|
},
|
|
47
42
|
];
|
|
48
|
-
/**
|
|
49
|
-
* Check if a string contains a weak cipher algorithm
|
|
50
|
-
*/
|
|
51
43
|
function findWeakCipher(value, additionalPatterns) {
|
|
52
|
-
// Check standard patterns
|
|
53
44
|
for (const pattern of WEAK_CIPHER_PATTERNS) {
|
|
54
45
|
if (pattern.pattern.test(value)) {
|
|
55
46
|
return pattern;
|
|
56
47
|
}
|
|
57
48
|
}
|
|
58
|
-
// Check additional patterns
|
|
59
49
|
for (const additionalPattern of additionalPatterns) {
|
|
60
50
|
const regex = new RegExp(`\\b${additionalPattern}\\b`, 'i');
|
|
61
51
|
if (regex.test(value)) {
|
|
@@ -137,28 +127,20 @@ exports.noWeakCipherAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
137
127
|
const { additionalWeakCiphers = [], allowInTests = false, } = options;
|
|
138
128
|
const filename = context.filename;
|
|
139
129
|
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
140
|
-
/**
|
|
141
|
-
* Check if a call expression uses a weak cipher
|
|
142
|
-
*/
|
|
143
130
|
function checkCallExpression(node) {
|
|
144
131
|
if (isTestFile)
|
|
145
132
|
return;
|
|
146
133
|
const cipherMethods = new Set(['createCipher', 'createCipheriv', 'createDecipher', 'createDecipheriv']);
|
|
147
|
-
// Check for crypto.createCipher*() pattern
|
|
148
134
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
149
135
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
150
136
|
cipherMethods.has(node.callee.property.name)) {
|
|
151
137
|
checkCipherArgument(node);
|
|
152
138
|
}
|
|
153
|
-
// Check for standalone createCipher*() pattern
|
|
154
139
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
155
140
|
cipherMethods.has(node.callee.name)) {
|
|
156
141
|
checkCipherArgument(node);
|
|
157
142
|
}
|
|
158
143
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Check the algorithm argument passed to createCipher*
|
|
161
|
-
*/
|
|
162
144
|
function checkCipherArgument(node) {
|
|
163
145
|
const firstArg = node.arguments[0];
|
|
164
146
|
if (firstArg?.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof firstArg.value === 'string') {
|
|
@@ -190,4 +172,3 @@ exports.noWeakCipherAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
190
172
|
};
|
|
191
173
|
},
|
|
192
174
|
});
|
|
193
|
-
//# sourceMappingURL=index.js.map
|