eslint-plugin-node-security 4.3.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/package.json +1 -1
- package/src/index.js +4 -1
- package/src/index.js.map +1 -1
- package/src/rules/detect-child-process/index.js +1 -1
- package/src/rules/detect-eval-with-expression/index.js +1 -1
- package/src/rules/no-cryptojs/index.js +1 -1
- package/src/rules/no-cryptojs/index.js.map +1 -1
- package/src/rules/no-cryptojs-weak-random/index.js +1 -1
- package/src/rules/no-dynamic-algorithm-selection/index.d.ts +26 -0
- package/src/rules/no-dynamic-algorithm-selection/index.js +85 -0
- package/src/rules/no-dynamic-algorithm-selection/index.js.map +1 -0
- package/src/rules/no-dynamic-dependency-loading/index.js +1 -1
- package/src/rules/no-math-random-crypto/index.js +1 -1
- package/src/rules/no-ssrf/index.js +1 -1
- package/src/rules/no-unsafe-dynamic-require/index.js +1 -1
- package/src/rules/no-weak-cipher-algorithm/index.js +1 -1
- package/src/rules/no-weak-hash-algorithm/index.js +1 -1
- package/src/rules/prefer-native-crypto/index.js +1 -1
- package/src/rules/prefer-native-crypto/index.js.map +1 -1
- package/src/rules/require-dependency-integrity/index.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
## [4.1.0] - 2026-05-03
|
|
2
2
|
|
|
3
|
+
## 4.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#190](https://github.com/ofri-peretz/eslint/pull/190) [`6bb476d`](https://github.com/ofri-peretz/eslint/commit/6bb476d232f85da8201b08d0a199c9267c3499e5) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - feat(node-security): add `no-dynamic-algorithm-selection` (CWE-327)
|
|
8
|
+
|
|
9
|
+
Disallow dynamic (non-literal) algorithm names in Node.js crypto functions.
|
|
10
|
+
A runtime-selected algorithm argument can allow a downgrade to a broken or
|
|
11
|
+
risky cryptographic algorithm (CWE-327: Use of a Broken or Risky
|
|
12
|
+
Cryptographic Algorithm). AST-structural — flags non-literal algorithm
|
|
13
|
+
arguments to the crypto APIs.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#215](https://github.com/ofri-peretz/eslint/pull/215) [`f42ea93`](https://github.com/ofri-peretz/eslint/commit/f42ea935555a558627dd61d1b013cd8509943c89) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - Align `no-dynamic-algorithm-selection`'s `meta.docs.cvss` (7.4) to the CVSS its
|
|
18
|
+
finding actually emits. The rule's message carries `CWE-327` and sets no
|
|
19
|
+
per-message `cvss`, so it inherits `CWE_MAPPING['CWE-327']` = 7.5 via
|
|
20
|
+
`enrichFromCWE` — docs now match the emitted value. Surfaced by the
|
|
21
|
+
cross-plugin `security-cvss-docs-consistency.lock.test.ts` lock (added in [#213](https://github.com/ofri-peretz/eslint/issues/213)),
|
|
22
|
+
which turned main red when this rule landed concurrently with the CVSS sweep.
|
|
23
|
+
Documentation-metadata only; no emitted finding changes.
|
|
24
|
+
|
|
25
|
+
- [#213](https://github.com/ofri-peretz/eslint/pull/213) [`391dbe6`](https://github.com/ofri-peretz/eslint/commit/391dbe6b39f78d549379218567cb959649f8c614) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - Align every security rule's `meta.docs.cvss` to the CVSS its finding actually
|
|
26
|
+
emits. The emitted machine-readable message sources its `CVSS:x` from
|
|
27
|
+
`CWE_MAPPING` via `formatLLMMessage` → `enrichFromCWE`, but the static
|
|
28
|
+
`meta.docs.cvss` documentation field had drifted on 45 rules across these 7
|
|
29
|
+
plugins — e.g. `no-hardcoded-credentials` documented `9.5` while emitting
|
|
30
|
+
`CVSS:9.8` (the value the published article and SARIF/LLM consumers already
|
|
31
|
+
read).
|
|
32
|
+
|
|
33
|
+
This corrects the **documentation metadata only** — no emitted finding changes.
|
|
34
|
+
Locked by `security-cvss-docs-consistency.lock.test.ts` (cross-plugin: every
|
|
35
|
+
security rule's `meta.docs.cvss` must equal the CVSS it emits), the
|
|
36
|
+
`no-hardcoded-credentials` rule lock (real ESLint `Linter` emission), and a
|
|
37
|
+
devkit `enrichFromCWE` contract test pinning `CWE-798 → 9.8`.
|
|
38
|
+
|
|
39
|
+
Follow-up (not in scope): 50 security rules document a CVSS that never appears
|
|
40
|
+
in any emitted message (their messages carry no CWE), and several rules emit the
|
|
41
|
+
generic CWE score where a rule-specific score may be warranted — both change
|
|
42
|
+
emitted output and are separate decisions.
|
|
43
|
+
|
|
3
44
|
## 4.3.0
|
|
4
45
|
|
|
5
46
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-node-security",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Security-focused ESLint plugin for Node.js built-in modules (fs, child_process, vm, path, Buffer). Detects command injection, path traversal, code execution vulnerabilities with AI-parseable error messages.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
package/src/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const no_arbitrary_file_access_1 = require("./rules/no-arbitrary-file-access");
|
|
|
18
18
|
const no_data_in_temp_storage_1 = require("./rules/no-data-in-temp-storage");
|
|
19
19
|
const no_ssrf_1 = require("./rules/no-ssrf");
|
|
20
20
|
const no_shell_injection_1 = require("./rules/no-shell-injection");
|
|
21
|
+
const no_dynamic_algorithm_selection_1 = require("./rules/no-dynamic-algorithm-selection");
|
|
21
22
|
// Migrated rules from secure-coding
|
|
22
23
|
const detect_suspicious_dependencies_1 = require("./rules/detect-suspicious-dependencies");
|
|
23
24
|
const lock_file_1 = require("./rules/lock-file");
|
|
@@ -55,6 +56,7 @@ exports.rules = {
|
|
|
55
56
|
'no-data-in-temp-storage': no_data_in_temp_storage_1.noDataInTempStorage,
|
|
56
57
|
'no-ssrf': no_ssrf_1.noSsrf,
|
|
57
58
|
'no-shell-injection': no_shell_injection_1.noShellInjection,
|
|
59
|
+
'no-dynamic-algorithm-selection': no_dynamic_algorithm_selection_1.noDynamicAlgorithmSelection,
|
|
58
60
|
// Migrated rules
|
|
59
61
|
'detect-suspicious-dependencies': detect_suspicious_dependencies_1.detectSuspiciousDependencies,
|
|
60
62
|
'lock-file': lock_file_1.lockFile,
|
|
@@ -83,7 +85,7 @@ exports.rules = {
|
|
|
83
85
|
exports.plugin = {
|
|
84
86
|
meta: {
|
|
85
87
|
name: 'eslint-plugin-node-security',
|
|
86
|
-
version: '4.
|
|
88
|
+
version: '4.4.0',
|
|
87
89
|
},
|
|
88
90
|
rules: exports.rules,
|
|
89
91
|
};
|
|
@@ -109,6 +111,7 @@ const recommendedRules = {
|
|
|
109
111
|
'node-security/no-data-in-temp-storage': 'error',
|
|
110
112
|
'node-security/no-ssrf': 'warn',
|
|
111
113
|
'node-security/no-shell-injection': 'error',
|
|
114
|
+
'node-security/no-dynamic-algorithm-selection': 'error',
|
|
112
115
|
// Migrated Rules
|
|
113
116
|
'node-security/detect-suspicious-dependencies': 'warn',
|
|
114
117
|
'node-security/lock-file': 'warn', // filesystem check — not pure AST; CI enforces this better
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,uEAAkE;AAClE,qFAA+E;AAC/E,2FAAoF;AACpF,iFAA2E;AAC3E,mEAA8D;AAC9D,uEAAkE;AAClE,6EAAwE;AACxE,qDAAgD;AAChD,+EAAyE;AACzE,6EAAsE;AACtE,6CAAyC;AACzC,mEAA8D;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -133,7 +133,7 @@ exports.detectChildProcess = (0, eslint_devkit_2.createRule)({
|
|
|
133
133
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/detect-child-process.md',
|
|
134
134
|
description: 'Detects child_process usage that may allow command injection',
|
|
135
135
|
cwe: 'CWE-78',
|
|
136
|
-
cvss: 9.
|
|
136
|
+
cvss: 9.8,
|
|
137
137
|
confidence: 'medium',
|
|
138
138
|
},
|
|
139
139
|
messages: {
|
|
@@ -59,7 +59,7 @@ exports.detectEvalWithExpression = (0, eslint_devkit_2.createRule)({
|
|
|
59
59
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/detect-eval-with-expression.md',
|
|
60
60
|
description: 'Detects eval(variable) which can allow an attacker to run arbitrary code',
|
|
61
61
|
cwe: 'CWE-95',
|
|
62
|
-
cvss: 9.
|
|
62
|
+
cvss: 9.8,
|
|
63
63
|
confidence: 'high',
|
|
64
64
|
},
|
|
65
65
|
messages: {
|
|
@@ -15,7 +15,7 @@ exports.noCryptojs = (0, eslint_devkit_1.createRule)({
|
|
|
15
15
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs.md',
|
|
16
16
|
description: 'Disallow deprecated crypto-js library (use native crypto instead)',
|
|
17
17
|
cwe: 'CWE-1104',
|
|
18
|
-
cvss: 5,
|
|
18
|
+
cvss: 5.3,
|
|
19
19
|
},
|
|
20
20
|
hasSuggestions: true,
|
|
21
21
|
messages: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rules/no-cryptojs/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAWH,4DAAsG;AAczF,QAAA,UAAU,GAAG,IAAA,0BAAU,EAA0B;IAC5D,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,GAAG,EAAE,gHAAgH;YACrH,WAAW,EAAE,mEAAmE;YAChF,GAAG,EAAE,UAAU;YACf,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rules/no-cryptojs/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ exports.noCryptojsWeakRandom = (0, eslint_devkit_1.createRule)({
|
|
|
15
15
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs-weak-random.md',
|
|
16
16
|
description: 'Disallow crypto-js WordArray.random() (CVE-2020-36732)',
|
|
17
17
|
cwe: 'CWE-338',
|
|
18
|
-
cvss:
|
|
18
|
+
cvss: 5.3,
|
|
19
19
|
},
|
|
20
20
|
hasSuggestions: true,
|
|
21
21
|
messages: {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* ESLint Rule: no-dynamic-algorithm-selection
|
|
7
|
+
* CWE-327: Use of a Broken or Risky Cryptographic Algorithm
|
|
8
|
+
*
|
|
9
|
+
* Detects crypto.createHash(), crypto.createCipheriv(), crypto.createSign(),
|
|
10
|
+
* and similar Node crypto APIs where the algorithm name comes from a dynamic
|
|
11
|
+
* value (variable, request param, config value) rather than a literal string.
|
|
12
|
+
*
|
|
13
|
+
* An attacker who controls the algorithm parameter can:
|
|
14
|
+
* - Downgrade to a weak algorithm (MD5, SHA1, RC4)
|
|
15
|
+
* - Cause a crash with an unsupported algorithm name
|
|
16
|
+
* - Bypass security controls that assume a strong algorithm is in use
|
|
17
|
+
*
|
|
18
|
+
* Detection: structural-api.
|
|
19
|
+
* crypto.createHash(req.query.algo) → fires (dynamic first arg)
|
|
20
|
+
* crypto.createHash('sha256') → silent (literal, checked separately)
|
|
21
|
+
* crypto.createHash(`sha256`) → silent (static template)
|
|
22
|
+
*/
|
|
23
|
+
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
24
|
+
export declare const noDynamicAlgorithmSelection: TSESLint.RuleModule<"dynamicAlgorithm", [], unknown, TSESLint.RuleListener> & {
|
|
25
|
+
name: string;
|
|
26
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.noDynamicAlgorithmSelection = void 0;
|
|
8
|
+
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
9
|
+
/** Node crypto functions whose first argument is the algorithm name. */
|
|
10
|
+
const CRYPTO_ALGORITHM_FUNCTIONS = new Set([
|
|
11
|
+
'createHash',
|
|
12
|
+
'createHmac',
|
|
13
|
+
'createSign',
|
|
14
|
+
'createVerify',
|
|
15
|
+
'createCipher',
|
|
16
|
+
'createCipheriv',
|
|
17
|
+
'createDecipher',
|
|
18
|
+
'createDecipheriv',
|
|
19
|
+
]);
|
|
20
|
+
exports.noDynamicAlgorithmSelection = (0, eslint_devkit_1.createRule)({
|
|
21
|
+
name: 'no-dynamic-algorithm-selection',
|
|
22
|
+
meta: {
|
|
23
|
+
type: 'problem',
|
|
24
|
+
docs: {
|
|
25
|
+
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-dynamic-algorithm-selection.md',
|
|
26
|
+
description: 'Disallow dynamic algorithm names in Node.js crypto functions (CWE-327)',
|
|
27
|
+
cwe: 'CWE-327',
|
|
28
|
+
// Match the CVSS the finding emits: the message sets no per-message
|
|
29
|
+
// cvss, so it inherits CWE_MAPPING['CWE-327'] (7.5) via enrichFromCWE.
|
|
30
|
+
// Locked by security-cvss-docs-consistency.lock.test.ts.
|
|
31
|
+
cvss: 7.5,
|
|
32
|
+
},
|
|
33
|
+
messages: {
|
|
34
|
+
dynamicAlgorithm: (0, eslint_devkit_1.formatLLMMessage)({
|
|
35
|
+
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
36
|
+
issueName: 'Dynamic Cryptographic Algorithm (CWE-327)',
|
|
37
|
+
cwe: 'CWE-327',
|
|
38
|
+
description: '`crypto.{{method}}()` receives a dynamic algorithm name. An attacker who controls this value can downgrade to a weak algorithm (MD5, SHA1, RC4) or cause a crash.',
|
|
39
|
+
severity: 'HIGH',
|
|
40
|
+
fix: 'Hard-code the algorithm name as a literal string (e.g. "sha256", "aes-256-gcm"). Use an allowlist if the algorithm must vary at runtime.',
|
|
41
|
+
documentationLink: 'https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html',
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
schema: [],
|
|
45
|
+
},
|
|
46
|
+
defaultOptions: [],
|
|
47
|
+
create(context) {
|
|
48
|
+
return {
|
|
49
|
+
CallExpression(node) {
|
|
50
|
+
const { callee, arguments: args } = node;
|
|
51
|
+
// Match crypto.method(algo) — MemberExpression where object is 'crypto'
|
|
52
|
+
if (callee.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression)
|
|
53
|
+
return;
|
|
54
|
+
if (callee.object.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier)
|
|
55
|
+
return;
|
|
56
|
+
if (callee.property.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier)
|
|
57
|
+
return;
|
|
58
|
+
const objectName = callee.object.name;
|
|
59
|
+
const methodName = callee.property.name;
|
|
60
|
+
if (objectName !== 'crypto')
|
|
61
|
+
return;
|
|
62
|
+
if (!CRYPTO_ALGORITHM_FUNCTIONS.has(methodName))
|
|
63
|
+
return;
|
|
64
|
+
const firstArg = args[0];
|
|
65
|
+
if (!firstArg)
|
|
66
|
+
return;
|
|
67
|
+
// String literal → already handled by no-weak-hash-algorithm for weak algos;
|
|
68
|
+
// a literal is always an intentional, auditable choice.
|
|
69
|
+
if (firstArg.type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
70
|
+
typeof firstArg.value === 'string')
|
|
71
|
+
return;
|
|
72
|
+
// Template literal without expressions → equivalent to literal, safe.
|
|
73
|
+
if (firstArg.type === eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral &&
|
|
74
|
+
firstArg.expressions.length === 0)
|
|
75
|
+
return;
|
|
76
|
+
context.report({
|
|
77
|
+
node: firstArg,
|
|
78
|
+
messageId: 'dynamicAlgorithm',
|
|
79
|
+
data: { method: methodName },
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rules/no-dynamic-algorithm-selection/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAsBH,4DAKkC;AAIlC,wEAAwE;AACxE,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,cAAc;IACd,gBAAgB;IAChB,gBAAgB;IAChB,kBAAkB;CACnB,CAAC,CAAC;AAEU,QAAA,2BAA2B,GAAG,IAAA,0BAAU,EAAiB;IACpE,IAAI,EAAE,gCAAgC;IACtC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,GAAG,EAAE,mIAAmI;YACxI,WAAW,EACT,wEAAwE;YAC1E,GAAG,EAAE,SAAS;YACd,oEAAoE;YACpE,uEAAuE;YACvE,yDAAyD;YACzD,IAAI,EAAE,GAAG;SACV;QACD,QAAQ,EAAE;YACR,gBAAgB,EAAE,IAAA,gCAAgB,EAAC;gBACjC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,2CAA2C;gBACtD,GAAG,EAAE,SAAS;gBACd,WAAW,EACT,mKAAmK;gBACrK,QAAQ,EAAE,MAAM;gBAChB,GAAG,EAAE,0IAA0I;gBAC/I,iBAAiB,EACf,uFAAuF;aAC1F,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAA6C;QAClD,OAAO;YACL,cAAc,CAAC,IAA6B;gBAC1C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;gBAEzC,wEAAwE;gBACxE,IAAI,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,gBAAgB;oBAAE,OAAO;gBAC5D,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBAAE,OAAO;gBAC7D,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBAAE,OAAO;gBAE/D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;gBACtC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAExC,IAAI,UAAU,KAAK,QAAQ;oBAAE,OAAO;gBACpC,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,UAAU,CAAC;oBAAE,OAAO;gBAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBAEtB,6EAA6E;gBAC7E,wDAAwD;gBACxD,IACE,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,OAAO;oBACxC,OAAQ,QAA6B,CAAC,KAAK,KAAK,QAAQ;oBACxD,OAAO;gBAET,sEAAsE;gBACtE,IACE,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,eAAe;oBAC/C,QAAqC,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;oBAC/D,OAAO;gBAET,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,kBAAkB;oBAC7B,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;iBAC7B,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -20,7 +20,7 @@ exports.noDynamicDependencyLoading = (0, eslint_devkit_1.createRule)({
|
|
|
20
20
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-dynamic-dependency-loading.md',
|
|
21
21
|
description: 'Prevent runtime dependency injection with dynamic paths',
|
|
22
22
|
cwe: 'CWE-1104',
|
|
23
|
-
cvss:
|
|
23
|
+
cvss: 5.3,
|
|
24
24
|
},
|
|
25
25
|
messages: {
|
|
26
26
|
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|
|
@@ -49,7 +49,7 @@ exports.noMathRandomCrypto = (0, eslint_devkit_1.createRule)({
|
|
|
49
49
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-math-random-crypto.md',
|
|
50
50
|
description: 'Disallow Math.random() for cryptographic purposes',
|
|
51
51
|
cwe: 'CWE-338',
|
|
52
|
-
cvss:
|
|
52
|
+
cvss: 5.3,
|
|
53
53
|
confidence: 'medium',
|
|
54
54
|
},
|
|
55
55
|
hasSuggestions: true,
|
|
@@ -141,7 +141,7 @@ exports.noSsrf = (0, eslint_devkit_1.createRule)({
|
|
|
141
141
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-ssrf.md',
|
|
142
142
|
description: 'Flags HTTP calls whose URL argument is an identifier with a user-input-sounding name — a heuristic prompt for code review, not a proof of SSRF',
|
|
143
143
|
cwe: 'CWE-918',
|
|
144
|
-
cvss:
|
|
144
|
+
cvss: 9.1,
|
|
145
145
|
},
|
|
146
146
|
messages: {
|
|
147
147
|
ssrfVulnerability: (0, eslint_devkit_1.formatLLMMessage)({
|
|
@@ -16,7 +16,7 @@ exports.noUnsafeDynamicRequire = (0, eslint_devkit_2.createRule)({
|
|
|
16
16
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-unsafe-dynamic-require.md',
|
|
17
17
|
description: 'Prevent unsafe dynamic require() calls that could enable code injection',
|
|
18
18
|
cwe: 'CWE-95',
|
|
19
|
-
cvss: 9.
|
|
19
|
+
cvss: 9.8,
|
|
20
20
|
},
|
|
21
21
|
hasSuggestions: false,
|
|
22
22
|
messages: {
|
|
@@ -77,7 +77,7 @@ exports.noWeakCipherAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
77
77
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-weak-cipher-algorithm.md',
|
|
78
78
|
description: 'Disallow weak cipher algorithms (DES, 3DES, RC4, Blowfish)',
|
|
79
79
|
cwe: 'CWE-327',
|
|
80
|
-
cvss:
|
|
80
|
+
cvss: 7.5,
|
|
81
81
|
},
|
|
82
82
|
hasSuggestions: true,
|
|
83
83
|
messages: {
|
|
@@ -65,7 +65,7 @@ exports.noWeakHashAlgorithm = (0, eslint_devkit_1.createRule)({
|
|
|
65
65
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-weak-hash-algorithm.md',
|
|
66
66
|
description: 'Disallow weak hash algorithms (MD5, SHA1, MD4)',
|
|
67
67
|
cwe: 'CWE-327',
|
|
68
|
-
cvss:
|
|
68
|
+
cvss: 7.5,
|
|
69
69
|
},
|
|
70
70
|
hasSuggestions: true,
|
|
71
71
|
messages: {
|
|
@@ -31,7 +31,7 @@ exports.preferNativeCrypto = (0, eslint_devkit_1.createRule)({
|
|
|
31
31
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/prefer-native-crypto.md',
|
|
32
32
|
description: 'Prefer native crypto over third-party libraries',
|
|
33
33
|
cwe: 'CWE-1104',
|
|
34
|
-
cvss: 5,
|
|
34
|
+
cvss: 5.3,
|
|
35
35
|
},
|
|
36
36
|
hasSuggestions: true,
|
|
37
37
|
messages: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rules/prefer-native-crypto/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAUH,4DAAsG;AActG,mEAAmE;AACnE,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,WAAW;IACX,UAAU;IACV,MAAM,EAAY,qCAAqC;IACvD,OAAO,EAAW,aAAa;IAC/B,YAAY;IACZ,WAAW;IACX,UAAU,EAAQ,wCAAwC;IAC1D,WAAW;IACX,WAAW;IACX,SAAS;IACT,QAAQ;IACR,aAAa;IACb,QAAQ;CACT,CAAC,CAAC;AAEU,QAAA,kBAAkB,GAAG,IAAA,0BAAU,EAA0B;IACpE,IAAI,EAAE,sBAAsB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,GAAG,EAAE,yHAAyH;YAC9H,WAAW,EAAE,iDAAiD;YAC9D,GAAG,EAAE,UAAU;YACf,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/rules/prefer-native-crypto/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ exports.requireDependencyIntegrity = (0, eslint_devkit_1.createRule)({
|
|
|
18
18
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/require-dependency-integrity.md',
|
|
19
19
|
description: 'Require SRI (Subresource Integrity) for CDN resources',
|
|
20
20
|
cwe: 'CWE-494',
|
|
21
|
-
cvss:
|
|
21
|
+
cvss: 8.1,
|
|
22
22
|
},
|
|
23
23
|
messages: {
|
|
24
24
|
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|