eslint-plugin-node-security 4.6.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 +1 -0
- package/package.json +5 -8
- package/src/index.d.ts +17 -10
- package/src/index.js +5 -36
- 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 +4 -80
- 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 +0 -13
- 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 -413
- 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-buffer-alloc/index.d.ts +0 -47
- package/src/rules/no-unsafe-buffer-alloc/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,59 +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
|
-
// `needle.get(url)` is covered here; the `needle('get', url)` verb-first form
|
|
23
|
-
// is not — the URL sits in argument 1, and this rule only reads argument 0.
|
|
24
14
|
const HTTP_CLIENT_OBJECTS = new Set([
|
|
25
15
|
'axios', 'got', 'superagent', 'request', 'http', 'https', 'undici', 'needle',
|
|
26
16
|
]);
|
|
27
|
-
// Function names that indicate URL validation
|
|
28
17
|
const VALIDATION_FUNCTION_NAMES = new Set([
|
|
29
18
|
'validateUrl', 'validateURL', 'isValidUrl', 'isSafeUrl', 'isAllowed',
|
|
30
19
|
'isValidURL', 'checkUrl', 'checkURL', 'sanitizeUrl', 'sanitizeURL',
|
|
31
20
|
]);
|
|
32
|
-
// Substrings in identifier names that suggest user input
|
|
33
21
|
const USER_INPUT_SUBSTRINGS = [
|
|
34
22
|
'url', 'endpoint', 'uri', 'href', 'link',
|
|
35
23
|
'target', 'dest', 'source', 'host',
|
|
36
24
|
'user', 'input', 'param',
|
|
37
25
|
];
|
|
38
|
-
/**
|
|
39
|
-
* Check if a function parameter name suggests user input
|
|
40
|
-
*/
|
|
41
26
|
function isUserInputParamName(name) {
|
|
42
27
|
const lower = name.toLowerCase();
|
|
43
28
|
return USER_INPUT_SUBSTRINGS.some(sub => lower.includes(sub));
|
|
44
29
|
}
|
|
45
|
-
// Object roots whose members carry attacker-controlled data in the common
|
|
46
|
-
// server frameworks: Express `req`/`request`, Koa `ctx`, Lambda `event`.
|
|
47
30
|
const REQUEST_ROOT_NAMES = new Set(['req', 'request', 'ctx', 'event']);
|
|
48
|
-
// Keys of a Node `http.request(options)` object that actually name a URL.
|
|
49
|
-
// `host`/`hostname`/`path`/`port` are deliberately absent: a helper that
|
|
50
|
-
// parameterises them is ordinary internal plumbing, not evidence of user flow.
|
|
51
31
|
const URL_OPTION_KEYS = new Set(['url', 'href', 'uri']);
|
|
52
|
-
/**
|
|
53
|
-
* True when the expression reads off a request object — `req.query.url`,
|
|
54
|
-
* `ctx.request.body.target`, `event.queryStringParameters.u`. Everything
|
|
55
|
-
* hanging off a request is untrusted, so the root name is the whole test.
|
|
56
|
-
*/
|
|
57
32
|
function isRequestSourced(node) {
|
|
58
33
|
let current = node;
|
|
59
34
|
while (current.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
@@ -63,26 +38,6 @@ function isRequestSourced(node) {
|
|
|
63
38
|
current.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
64
39
|
REQUEST_ROOT_NAMES.has(current.name.toLowerCase()));
|
|
65
40
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Does the URL argument carry untrusted data into the request?
|
|
68
|
-
*
|
|
69
|
-
* The rule reports on evidence of flow, never on the mere presence of a
|
|
70
|
-
* dynamic argument. Three shapes qualify:
|
|
71
|
-
*
|
|
72
|
-
* 1. The whole argument is a user-input-named identifier — `fetch(userUrl)`.
|
|
73
|
-
* This is the rule's documented naming heuristic: a bare identifier in
|
|
74
|
-
* URL position *is* the URL.
|
|
75
|
-
* 2. Any part of the expression reads from a request object —
|
|
76
|
-
* `fetch(req.query.url)`, `https.request({ host: req.query.h })`.
|
|
77
|
-
* 3. A template literal URL interpolates either of the above —
|
|
78
|
-
* `fetch(\`https://\${userHost}/x\`)`.
|
|
79
|
-
*
|
|
80
|
-
* Everything else is not evidence. In particular an options object whose
|
|
81
|
-
* fields are plain locals — `https.request({ host, path, method: 'GET' })`,
|
|
82
|
-
* benchmarks/corpus/CWE-444/safe/request-default-parser.js — used to be
|
|
83
|
-
* reported unconditionally because a non-Identifier argument bypassed the
|
|
84
|
-
* name gate entirely.
|
|
85
|
-
*/
|
|
86
41
|
function carriesUntrustedUrl(node) {
|
|
87
42
|
switch (node.type) {
|
|
88
43
|
case eslint_devkit_1.AST_NODE_TYPES.Identifier:
|
|
@@ -91,15 +46,11 @@ function carriesUntrustedUrl(node) {
|
|
|
91
46
|
return isRequestSourced(node);
|
|
92
47
|
case eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral:
|
|
93
48
|
return node.expressions.some(carriesUntrustedUrl);
|
|
94
|
-
// `new URL(userUrl)` / `String(req.query.url)` — inspect the arguments.
|
|
95
49
|
case eslint_devkit_1.AST_NODE_TYPES.CallExpression:
|
|
96
50
|
case eslint_devkit_1.AST_NODE_TYPES.NewExpression:
|
|
97
51
|
return node.arguments.some(carriesUntrustedUrl);
|
|
98
|
-
// `'https://host' + userPath`
|
|
99
52
|
case eslint_devkit_1.AST_NODE_TYPES.BinaryExpression:
|
|
100
53
|
return carriesUntrustedUrl(node.left) || carriesUntrustedUrl(node.right);
|
|
101
|
-
// `http.request({ url: x, host: y })` — only URL-naming keys count by
|
|
102
|
-
// name; every other key still counts if its value is request-sourced.
|
|
103
54
|
case eslint_devkit_1.AST_NODE_TYPES.ObjectExpression:
|
|
104
55
|
return node.properties.some(property => {
|
|
105
56
|
if (property.type !== eslint_devkit_1.AST_NODE_TYPES.Property)
|
|
@@ -118,24 +69,17 @@ function carriesUntrustedUrl(node) {
|
|
|
118
69
|
return false;
|
|
119
70
|
}
|
|
120
71
|
}
|
|
121
|
-
/**
|
|
122
|
-
* AST-based check: does this node contain a validation pattern?
|
|
123
|
-
* Walks the node tree looking for known validation constructs.
|
|
124
|
-
*/
|
|
125
72
|
function nodeContainsValidation(node) {
|
|
126
|
-
// new URL(x) — URL constructor (parsing/validation)
|
|
127
73
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.NewExpression &&
|
|
128
74
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
129
75
|
node.callee.name === 'URL') {
|
|
130
76
|
return true;
|
|
131
77
|
}
|
|
132
|
-
// validateUrl(x), isValidUrl(x), etc.
|
|
133
78
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
134
79
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
135
80
|
VALIDATION_FUNCTION_NAMES.has(node.callee.name)) {
|
|
136
81
|
return true;
|
|
137
82
|
}
|
|
138
|
-
// arr.includes(x), set.has(x), x.startsWith('...'), regex.test(x)
|
|
139
83
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
140
84
|
node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
141
85
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
@@ -144,7 +88,6 @@ function nodeContainsValidation(node) {
|
|
|
144
88
|
return true;
|
|
145
89
|
}
|
|
146
90
|
}
|
|
147
|
-
// hostname === '...' or host === '...'
|
|
148
91
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.BinaryExpression &&
|
|
149
92
|
(node.operator === '===' || node.operator === '==') &&
|
|
150
93
|
((node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
@@ -155,13 +98,10 @@ function nodeContainsValidation(node) {
|
|
|
155
98
|
(node.right.property.name === 'hostname' || node.right.property.name === 'host')))) {
|
|
156
99
|
return true;
|
|
157
100
|
}
|
|
158
|
-
// throw new Error(...) — guard clause
|
|
159
101
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement) {
|
|
160
102
|
return true;
|
|
161
103
|
}
|
|
162
|
-
// Keys to skip: non-child properties that cause circular refs or aren't AST children
|
|
163
104
|
const SKIP_KEYS = new Set(['parent', 'range', 'loc', 'tokens', 'comments', 'start', 'end']);
|
|
164
|
-
// Recurse into child nodes
|
|
165
105
|
for (const key of Object.keys(node)) {
|
|
166
106
|
if (SKIP_KEYS.has(key))
|
|
167
107
|
continue;
|
|
@@ -181,11 +121,7 @@ function nodeContainsValidation(node) {
|
|
|
181
121
|
}
|
|
182
122
|
return false;
|
|
183
123
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Check if there is URL validation before the HTTP call using AST walking
|
|
186
|
-
*/
|
|
187
124
|
function hasValidationBefore(node) {
|
|
188
|
-
// Walk up to find the containing block
|
|
189
125
|
let current = node.parent;
|
|
190
126
|
while (current) {
|
|
191
127
|
const parent = current.parent;
|
|
@@ -194,14 +130,12 @@ function hasValidationBefore(node) {
|
|
|
194
130
|
if (parent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement || parent.type === eslint_devkit_1.AST_NODE_TYPES.Program) {
|
|
195
131
|
const body = parent.body;
|
|
196
132
|
const idx = body.indexOf(current);
|
|
197
|
-
// Check previous sibling statements for validation patterns
|
|
198
133
|
for (let i = idx - 1; i >= 0 && i >= idx - 10; i--) {
|
|
199
134
|
if (nodeContainsValidation(body[i])) {
|
|
200
135
|
return true;
|
|
201
136
|
}
|
|
202
137
|
}
|
|
203
138
|
}
|
|
204
|
-
// Check if inside an if-block where the condition contains validation
|
|
205
139
|
if (parent.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement && parent.test) {
|
|
206
140
|
if (nodeContainsValidation(parent.test)) {
|
|
207
141
|
return true;
|
|
@@ -255,12 +189,10 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
255
189
|
return {
|
|
256
190
|
CallExpression(node) {
|
|
257
191
|
let isHttpCall = false;
|
|
258
|
-
// 1. Direct function call: fetch(url), got(url)
|
|
259
192
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
260
193
|
HTTP_CLIENT_FUNCTIONS.has(node.callee.name)) {
|
|
261
194
|
isHttpCall = true;
|
|
262
195
|
}
|
|
263
|
-
// 2. Method call: axios.get(url), http.request(url)
|
|
264
196
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
265
197
|
node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
266
198
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
@@ -270,19 +202,12 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
270
202
|
}
|
|
271
203
|
if (!isHttpCall)
|
|
272
204
|
return;
|
|
273
|
-
// Check the first argument (the URL)
|
|
274
205
|
const urlArg = node.arguments[0];
|
|
275
206
|
if (!urlArg)
|
|
276
207
|
return;
|
|
277
|
-
// Static URLs — fetch('https://api.example.com'), fetch(`https://…`) —
|
|
278
|
-
// carry nothing untrusted and fall out at the evidence gate below.
|
|
279
|
-
// Check if there is URL validation before this call
|
|
280
208
|
if (hasValidationBefore(node)) {
|
|
281
209
|
return;
|
|
282
210
|
}
|
|
283
|
-
// Require evidence that untrusted data reaches the URL. Applies to
|
|
284
|
-
// every argument shape — an options object or a template literal used
|
|
285
|
-
// to bypass this gate entirely and report unconditionally.
|
|
286
211
|
if (!carriesUntrustedUrl(urlArg)) {
|
|
287
212
|
return;
|
|
288
213
|
}
|
|
@@ -294,4 +219,3 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
294
219
|
};
|
|
295
220
|
},
|
|
296
221
|
});
|
|
297
|
-
//# 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
|
|
@@ -1,13 +1,7 @@
|
|
|
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.noUnsafeBufferAlloc = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
/** The two uninitialized-memory allocators on `Buffer`. */
|
|
11
5
|
const UNSAFE_ALLOCATORS = new Set(['allocUnsafe', 'allocUnsafeSlow']);
|
|
12
6
|
exports.noUnsafeBufferAlloc = (0, eslint_devkit_1.createRule)({
|
|
13
7
|
name: 'no-unsafe-buffer-alloc',
|
|
@@ -49,10 +43,6 @@ exports.noUnsafeBufferAlloc = (0, eslint_devkit_1.createRule)({
|
|
|
49
43
|
},
|
|
50
44
|
defaultOptions: [],
|
|
51
45
|
create(context) {
|
|
52
|
-
/**
|
|
53
|
-
* True when the call's result is immediately zeroed in the same
|
|
54
|
-
* expression: `Buffer.allocUnsafe(n).fill(0)`. Parent-node shape only.
|
|
55
|
-
*/
|
|
56
46
|
function isFilledInPlace(node) {
|
|
57
47
|
const parent = node.parent;
|
|
58
48
|
if (parent?.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression ||
|
|
@@ -62,8 +52,6 @@ exports.noUnsafeBufferAlloc = (0, eslint_devkit_1.createRule)({
|
|
|
62
52
|
parent.property.name !== 'fill') {
|
|
63
53
|
return false;
|
|
64
54
|
}
|
|
65
|
-
// `.fill` must actually be invoked — `f(buf.fill)` passes the method
|
|
66
|
-
// around, it does not zero anything.
|
|
67
55
|
const grandparent = parent.parent;
|
|
68
56
|
return (grandparent?.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
69
57
|
grandparent.callee === parent);
|
|
@@ -97,4 +85,3 @@ exports.noUnsafeBufferAlloc = (0, eslint_devkit_1.createRule)({
|
|
|
97
85
|
};
|
|
98
86
|
},
|
|
99
87
|
});
|
|
100
|
-
//# 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.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
|
|
@@ -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.noWeakHashAlgorithm = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -33,17 +28,12 @@ const WEAK_HASH_PATTERNS = [
|
|
|
33
28
|
replacement: 'sha256',
|
|
34
29
|
},
|
|
35
30
|
];
|
|
36
|
-
/**
|
|
37
|
-
* Check if a string contains a weak hash algorithm
|
|
38
|
-
*/
|
|
39
31
|
function findWeakHash(value, additionalPatterns) {
|
|
40
|
-
// Check standard patterns
|
|
41
32
|
for (const pattern of WEAK_HASH_PATTERNS) {
|
|
42
33
|
if (pattern.pattern.test(value)) {
|
|
43
34
|
return pattern;
|
|
44
35
|
}
|
|
45
36
|
}
|
|
46
|
-
// Check additional patterns
|
|
47
37
|
for (const additionalPattern of additionalPatterns) {
|
|
48
38
|
const regex = new RegExp(`\\b${additionalPattern}\\b`, 'i');
|
|
49
39
|
if (regex.test(value)) {
|
|
@@ -133,29 +123,21 @@ exports.noWeakHashAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
133
123
|
const { additionalWeakAlgorithms = [], allowInTests = false, } = options;
|
|
134
124
|
const filename = context.filename;
|
|
135
125
|
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
136
|
-
/**
|
|
137
|
-
* Check if a call expression uses a weak hash
|
|
138
|
-
*/
|
|
139
126
|
function checkCallExpression(node) {
|
|
140
127
|
if (isTestFile)
|
|
141
128
|
return;
|
|
142
|
-
// Check for crypto.createHash() pattern
|
|
143
129
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
144
130
|
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
145
131
|
node.callee.property.name === 'createHash') {
|
|
146
132
|
checkHashArgument(node);
|
|
147
133
|
}
|
|
148
|
-
// Check for standalone createHash() pattern
|
|
149
134
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
150
135
|
node.callee.name === 'createHash') {
|
|
151
136
|
checkHashArgument(node);
|
|
152
137
|
}
|
|
153
|
-
// Check for crypto-hash package: sha1(), md5()
|
|
154
138
|
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
155
139
|
const funcName = node.callee.name.toLowerCase();
|
|
156
140
|
if (funcName === 'sha1' || funcName === 'md5' || funcName === 'md4') {
|
|
157
|
-
// funcName is one of sha1/md5/md4, each of which always matches a
|
|
158
|
-
// WEAK_HASH_PATTERNS entry, so findWeakHash cannot return null here.
|
|
159
141
|
const weakPattern = findWeakHash(funcName, additionalWeakAlgorithms);
|
|
160
142
|
context.report({
|
|
161
143
|
node,
|
|
@@ -179,9 +161,6 @@ exports.noWeakHashAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
179
161
|
}
|
|
180
162
|
}
|
|
181
163
|
}
|
|
182
|
-
/**
|
|
183
|
-
* Check the algorithm argument passed to createHash
|
|
184
|
-
*/
|
|
185
164
|
function checkHashArgument(node) {
|
|
186
165
|
for (const arg of node.arguments) {
|
|
187
166
|
if (arg.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof arg.value === 'string') {
|
|
@@ -218,4 +197,3 @@ exports.noWeakHashAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
218
197
|
};
|
|
219
198
|
},
|
|
220
199
|
});
|
|
221
|
-
//# sourceMappingURL=index.js.map
|