eslint-plugin-node-security 4.7.3 → 4.8.1
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/package.json +2 -2
- package/src/index.js +1 -95
- package/src/oxlint.js +1 -3
- package/src/rules/detect-child-process/index.js +1 -625
- package/src/rules/detect-eval-with-expression/index.js +1 -364
- package/src/rules/detect-non-literal-fs-filename/index.js +1 -431
- package/src/rules/detect-suspicious-dependencies/index.js +1 -69
- package/src/rules/lock-file/index.js +1 -92
- package/src/rules/no-arbitrary-file-access/index.js +1 -152
- package/src/rules/no-buffer-overread/index.js +1 -543
- package/src/rules/no-cryptojs/index.js +1 -99
- package/src/rules/no-cryptojs-weak-random/index.js +1 -103
- package/src/rules/no-data-in-temp-storage/index.js +1 -85
- package/src/rules/no-deprecated-buffer/index.js +1 -84
- package/src/rules/no-deprecated-cipher-method/index.js +1 -112
- package/src/rules/no-dynamic-algorithm-selection/index.js +1 -72
- package/src/rules/no-dynamic-command-string/index.js +1 -201
- package/src/rules/no-dynamic-dependency-loading/index.js +1 -45
- package/src/rules/no-dynamic-require/index.js +1 -96
- package/src/rules/no-ecb-mode/index.js +1 -108
- package/src/rules/no-insecure-key-derivation/index.js +1 -109
- package/src/rules/no-insecure-rsa-padding/index.js +1 -104
- package/src/rules/no-math-random-crypto/index.js +1 -192
- package/src/rules/no-self-signed-certs/index.js +1 -110
- package/src/rules/no-sha1-hash/index.js +1 -121
- package/src/rules/no-shell-injection/index.js +1 -68
- package/src/rules/no-ssrf/index.js +1 -221
- package/src/rules/no-static-iv/index.js +1 -129
- package/src/rules/no-timing-unsafe-compare/index.js +1 -106
- package/src/rules/no-toctou-vulnerability/index.js +1 -195
- package/src/rules/no-unsafe-buffer-alloc/index.js +1 -87
- package/src/rules/no-unsafe-dynamic-require/index.js +1 -93
- package/src/rules/no-weak-cipher-algorithm/index.js +1 -174
- package/src/rules/no-weak-hash-algorithm/index.js +1 -199
- package/src/rules/no-zip-slip/index.js +1 -410
- package/src/rules/prefer-native-crypto/index.js +1 -119
- package/src/rules/require-dependency-integrity/index.js +1 -62
- package/src/rules/require-secure-credential-storage/index.js +1 -45
- package/src/rules/require-secure-deletion/index.js +1 -82
- package/src/rules/require-storage-encryption/index.js +1 -45
- package/src/types/index.js +1 -2
|
@@ -1,99 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noCryptojs = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noCryptojs = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-cryptojs',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'suggestion',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs.md',
|
|
11
|
-
description: 'Disallow deprecated crypto-js library (use native crypto instead)',
|
|
12
|
-
cwe: 'CWE-1104',
|
|
13
|
-
cvss: 5.3,
|
|
14
|
-
},
|
|
15
|
-
hasSuggestions: true,
|
|
16
|
-
messages: {
|
|
17
|
-
deprecatedCryptojs: (0, eslint_devkit_1.formatLLMMessage)({
|
|
18
|
-
icon: eslint_devkit_1.MessageIcons.WARNING,
|
|
19
|
-
issueName: 'Deprecated crypto-js library',
|
|
20
|
-
cwe: 'CWE-1104',
|
|
21
|
-
description: 'crypto-js is no longer maintained (last update: 2022). Future vulnerabilities will not be patched.',
|
|
22
|
-
severity: 'MEDIUM',
|
|
23
|
-
fix: 'Migrate to native Node.js crypto module or Web Crypto API',
|
|
24
|
-
documentationLink: 'https://nodejs.org/api/crypto.html',
|
|
25
|
-
}),
|
|
26
|
-
useNativeCrypto: (0, eslint_devkit_1.formatLLMMessage)({
|
|
27
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
28
|
-
issueName: 'Use Node.js crypto',
|
|
29
|
-
description: 'Node.js crypto module is maintained by the Node.js core team',
|
|
30
|
-
severity: 'LOW',
|
|
31
|
-
fix: 'import crypto from "node:crypto"',
|
|
32
|
-
documentationLink: 'https://nodejs.org/api/crypto.html',
|
|
33
|
-
}),
|
|
34
|
-
useWebCrypto: (0, eslint_devkit_1.formatLLMMessage)({
|
|
35
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
36
|
-
issueName: 'Use Web Crypto API',
|
|
37
|
-
description: 'Web Crypto API works in browsers and Node.js',
|
|
38
|
-
severity: 'LOW',
|
|
39
|
-
fix: 'globalThis.crypto.subtle',
|
|
40
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API',
|
|
41
|
-
}),
|
|
42
|
-
},
|
|
43
|
-
schema: [
|
|
44
|
-
{
|
|
45
|
-
type: 'object',
|
|
46
|
-
properties: {
|
|
47
|
-
severity: {
|
|
48
|
-
type: 'string',
|
|
49
|
-
enum: ['error', 'warn'],
|
|
50
|
-
default: 'warn',
|
|
51
|
-
description: 'Severity level for the rule',
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
additionalProperties: false,
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
defaultOptions: [
|
|
59
|
-
{
|
|
60
|
-
severity: 'warn',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
create(context) {
|
|
64
|
-
function reportDeprecatedLibrary(node) {
|
|
65
|
-
context.report({
|
|
66
|
-
node,
|
|
67
|
-
messageId: 'deprecatedCryptojs',
|
|
68
|
-
suggest: [
|
|
69
|
-
{
|
|
70
|
-
messageId: 'useNativeCrypto',
|
|
71
|
-
fix: () => null,
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
messageId: 'useWebCrypto',
|
|
75
|
-
fix: () => null,
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return {
|
|
81
|
-
ImportDeclaration(node) {
|
|
82
|
-
if (typeof node.source.value === 'string' &&
|
|
83
|
-
(node.source.value === 'crypto-js' || node.source.value.startsWith('crypto-js/'))) {
|
|
84
|
-
reportDeprecatedLibrary(node);
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
CallExpression(node) {
|
|
88
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
89
|
-
node.callee.name === 'require' &&
|
|
90
|
-
node.arguments.length === 1 &&
|
|
91
|
-
node.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
92
|
-
typeof node.arguments[0].value === 'string' &&
|
|
93
|
-
(node.arguments[0].value === 'crypto-js' || node.arguments[0].value.startsWith('crypto-js/'))) {
|
|
94
|
-
reportDeprecatedLibrary(node);
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
},
|
|
99
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCryptojs=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noCryptojs=(0,eslint_devkit_1.createRule)({name:"no-cryptojs",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs.md",description:"Disallow deprecated crypto-js library (use native crypto instead)",cwe:"CWE-1104",cvss:5.3},hasSuggestions:true,messages:{deprecatedCryptojs:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Deprecated crypto-js library",cwe:"CWE-1104",description:"crypto-js is no longer maintained (last update: 2022). Future vulnerabilities will not be patched.",severity:"MEDIUM",fix:"Migrate to native Node.js crypto module or Web Crypto API",documentationLink:"https://nodejs.org/api/crypto.html"}),useNativeCrypto:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Node.js crypto",description:"Node.js crypto module is maintained by the Node.js core team",severity:"LOW",fix:'import crypto from "node:crypto"',documentationLink:"https://nodejs.org/api/crypto.html"}),useWebCrypto:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Web Crypto API",description:"Web Crypto API works in browsers and Node.js",severity:"LOW",fix:"globalThis.crypto.subtle",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API"})},schema:[{type:"object",properties:{severity:{type:"string",enum:["error","warn"],default:"warn",description:"Severity level for the rule"}},additionalProperties:false}]},defaultOptions:[{severity:"warn"}],create(context){function reportDeprecatedLibrary(node){context.report({node,messageId:"deprecatedCryptojs",suggest:[{messageId:"useNativeCrypto",fix:()=>null},{messageId:"useWebCrypto",fix:()=>null}]})}return{ImportDeclaration(node){if(typeof node.source.value==="string"&&(node.source.value==="crypto-js"||node.source.value.startsWith("crypto-js/"))){reportDeprecatedLibrary(node)}},CallExpression(node){if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&node.callee.name==="require"&&node.arguments.length===1&&node.arguments[0].type===eslint_devkit_1.AST_NODE_TYPES.Literal&&typeof node.arguments[0].value==="string"&&(node.arguments[0].value==="crypto-js"||node.arguments[0].value.startsWith("crypto-js/"))){reportDeprecatedLibrary(node)}}}}});
|
|
@@ -1,103 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noCryptojsWeakRandom = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noCryptojsWeakRandom = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-cryptojs-weak-random',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'problem',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs-weak-random.md',
|
|
11
|
-
description: 'Disallow crypto-js WordArray.random() (CVE-2020-36732)',
|
|
12
|
-
cwe: 'CWE-338',
|
|
13
|
-
cvss: 5.3,
|
|
14
|
-
},
|
|
15
|
-
hasSuggestions: true,
|
|
16
|
-
messages: {
|
|
17
|
-
weakRandom: (0, eslint_devkit_1.formatLLMMessage)({
|
|
18
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
19
|
-
issueName: 'Weak random in crypto-js',
|
|
20
|
-
cwe: 'CWE-338',
|
|
21
|
-
description: 'CryptoJS.lib.WordArray.random() was insecure in versions < 3.2.1 (CVE-2020-36732). Used Math.random() instead of CSPRNG.',
|
|
22
|
-
severity: 'CRITICAL',
|
|
23
|
-
fix: 'Use crypto.randomBytes() from Node.js or crypto.getRandomValues() in browsers',
|
|
24
|
-
documentationLink: 'https://nvd.nist.gov/vuln/detail/CVE-2020-36732',
|
|
25
|
-
}),
|
|
26
|
-
useNativeRandom: (0, eslint_devkit_1.formatLLMMessage)({
|
|
27
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
28
|
-
issueName: 'Use native randomBytes',
|
|
29
|
-
description: 'Use cryptographically secure random from native crypto',
|
|
30
|
-
severity: 'LOW',
|
|
31
|
-
fix: 'crypto.randomBytes(32)',
|
|
32
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptorandombytessize-callback',
|
|
33
|
-
}),
|
|
34
|
-
},
|
|
35
|
-
schema: [
|
|
36
|
-
{
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {
|
|
39
|
-
allowInTests: {
|
|
40
|
-
type: 'boolean',
|
|
41
|
-
default: false,
|
|
42
|
-
description: 'Allow in test files',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
additionalProperties: false,
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
},
|
|
49
|
-
defaultOptions: [
|
|
50
|
-
{
|
|
51
|
-
allowInTests: false,
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
create(context, [options = {}]) {
|
|
55
|
-
const { allowInTests = false } = options;
|
|
56
|
-
const filename = context.filename;
|
|
57
|
-
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
58
|
-
function checkCallExpression(node) {
|
|
59
|
-
if (isTestFile)
|
|
60
|
-
return;
|
|
61
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
62
|
-
const callee = node.callee;
|
|
63
|
-
if (callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
64
|
-
callee.property.name === 'random') {
|
|
65
|
-
if (callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier && callee.object.name === 'WordArray') {
|
|
66
|
-
reportWeakRandom(node);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (callee.object.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
70
|
-
const innerObj = callee.object;
|
|
71
|
-
if (innerObj.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
72
|
-
innerObj.property.name === 'WordArray') {
|
|
73
|
-
reportWeakRandom(node);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
80
|
-
node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
81
|
-
node.callee.object.name === 'CryptoJS' &&
|
|
82
|
-
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
83
|
-
node.callee.property.name === 'random') {
|
|
84
|
-
reportWeakRandom(node);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function reportWeakRandom(node) {
|
|
88
|
-
context.report({
|
|
89
|
-
node,
|
|
90
|
-
messageId: 'weakRandom',
|
|
91
|
-
suggest: [
|
|
92
|
-
{
|
|
93
|
-
messageId: 'useNativeRandom',
|
|
94
|
-
fix: () => null,
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
CallExpression: checkCallExpression,
|
|
101
|
-
};
|
|
102
|
-
},
|
|
103
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCryptojsWeakRandom=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noCryptojsWeakRandom=(0,eslint_devkit_1.createRule)({name:"no-cryptojs-weak-random",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-cryptojs-weak-random.md",description:"Disallow crypto-js WordArray.random() (CVE-2020-36732)",cwe:"CWE-338",cvss:5.3},hasSuggestions:true,messages:{weakRandom:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Weak random in crypto-js",cwe:"CWE-338",description:"CryptoJS.lib.WordArray.random() was insecure in versions < 3.2.1 (CVE-2020-36732). Used Math.random() instead of CSPRNG.",severity:"CRITICAL",fix:"Use crypto.randomBytes() from Node.js or crypto.getRandomValues() in browsers",documentationLink:"https://nvd.nist.gov/vuln/detail/CVE-2020-36732"}),useNativeRandom:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use native randomBytes",description:"Use cryptographically secure random from native crypto",severity:"LOW",fix:"crypto.randomBytes(32)",documentationLink:"https://nodejs.org/api/crypto.html#cryptorandombytessize-callback"})},schema:[{type:"object",properties:{allowInTests:{type:"boolean",default:false,description:"Allow in test files"}},additionalProperties:false}]},defaultOptions:[{allowInTests:false}],create(context,[options={}]){const{allowInTests=false}=options;const filename=context.filename;const isTestFile=allowInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);function checkCallExpression(node){if(isTestFile)return;if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression){const callee=node.callee;if(callee.property.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&callee.property.name==="random"){if(callee.object.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&callee.object.name==="WordArray"){reportWeakRandom(node);return}if(callee.object.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression){const innerObj=callee.object;if(innerObj.property.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&innerObj.property.name==="WordArray"){reportWeakRandom(node);return}}}}if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression&&node.callee.object.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&node.callee.object.name==="CryptoJS"&&node.callee.property.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&node.callee.property.name==="random"){reportWeakRandom(node)}}function reportWeakRandom(node){context.report({node,messageId:"weakRandom",suggest:[{messageId:"useNativeRandom",fix:()=>null}]})}return{CallExpression:checkCallExpression}}});
|
|
@@ -1,85 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noDataInTempStorage = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const DEFAULT_TEMP_PATHS = ['/tmp', '/var/tmp', 'temp/', '/temp'];
|
|
6
|
-
exports.noDataInTempStorage = (0, eslint_devkit_1.createRule)({
|
|
7
|
-
name: 'no-data-in-temp-storage',
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'problem',
|
|
10
|
-
docs: {
|
|
11
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-data-in-temp-storage.md',
|
|
12
|
-
description: 'Prevent sensitive data in temp directories',
|
|
13
|
-
cwe: 'CWE-312',
|
|
14
|
-
cvss: 7.5,
|
|
15
|
-
},
|
|
16
|
-
messages: {
|
|
17
|
-
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|
|
18
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
19
|
-
issueName: 'Temp Storage Data',
|
|
20
|
-
cwe: 'CWE-312',
|
|
21
|
-
description: 'Sensitive data written to temp directory - not secure',
|
|
22
|
-
severity: 'HIGH',
|
|
23
|
-
fix: 'Use secure storage location or encrypt data before writing',
|
|
24
|
-
documentationLink: 'https://cwe.mitre.org/data/definitions/312.html',
|
|
25
|
-
})
|
|
26
|
-
},
|
|
27
|
-
schema: [
|
|
28
|
-
{
|
|
29
|
-
type: 'object',
|
|
30
|
-
properties: {
|
|
31
|
-
tempPaths: {
|
|
32
|
-
type: 'array',
|
|
33
|
-
items: { type: 'string' },
|
|
34
|
-
description: 'Custom list of temporary paths to flag'
|
|
35
|
-
},
|
|
36
|
-
ignoreFiles: {
|
|
37
|
-
type: 'array',
|
|
38
|
-
items: { type: 'string' },
|
|
39
|
-
description: 'List of files or patterns to ignore'
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
additionalProperties: false
|
|
43
|
-
}
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
defaultOptions: [{}],
|
|
47
|
-
create(context) {
|
|
48
|
-
const options = context.options[0] || {};
|
|
49
|
-
const tempPaths = options.tempPaths || DEFAULT_TEMP_PATHS;
|
|
50
|
-
const ignoreFiles = options.ignoreFiles || [];
|
|
51
|
-
const filename = context.filename;
|
|
52
|
-
if (ignoreFiles.some(pattern => filename.includes(pattern))) {
|
|
53
|
-
return {};
|
|
54
|
-
}
|
|
55
|
-
function report(node) {
|
|
56
|
-
context.report({ node, messageId: 'violationDetected' });
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
CallExpression(node) {
|
|
60
|
-
if (node.callee.type === 'MemberExpression' &&
|
|
61
|
-
node.callee.object.type === 'Identifier' &&
|
|
62
|
-
node.callee.object.name === 'fs' &&
|
|
63
|
-
node.callee.property.type === 'Identifier' &&
|
|
64
|
-
['writeFileSync', 'writeFile'].includes(node.callee.property.name)) {
|
|
65
|
-
const pathArg = node.arguments[0];
|
|
66
|
-
if (pathArg && pathArg.type === 'Literal' && typeof pathArg.value === 'string') {
|
|
67
|
-
if (tempPaths.some(tp => pathArg.value.includes(tp))) {
|
|
68
|
-
report(pathArg);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
Literal(node) {
|
|
74
|
-
if (typeof node.value === 'string') {
|
|
75
|
-
if (tempPaths.some(tp => node.value.includes(tp))) {
|
|
76
|
-
const parent = node.parent;
|
|
77
|
-
if (parent?.type === 'VariableDeclarator' || parent?.type === 'AssignmentExpression') {
|
|
78
|
-
report(node);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
},
|
|
85
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noDataInTempStorage=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const DEFAULT_TEMP_PATHS=["/tmp","/var/tmp","temp/","/temp"];exports.noDataInTempStorage=(0,eslint_devkit_1.createRule)({name:"no-data-in-temp-storage",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-data-in-temp-storage.md",description:"Prevent sensitive data in temp directories",cwe:"CWE-312",cvss:7.5},messages:{violationDetected:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Temp Storage Data",cwe:"CWE-312",description:"Sensitive data written to temp directory - not secure",severity:"HIGH",fix:"Use secure storage location or encrypt data before writing",documentationLink:"https://cwe.mitre.org/data/definitions/312.html"})},schema:[{type:"object",properties:{tempPaths:{type:"array",items:{type:"string"},description:"Custom list of temporary paths to flag"},ignoreFiles:{type:"array",items:{type:"string"},description:"List of files or patterns to ignore"}},additionalProperties:false}]},defaultOptions:[{}],create(context){const options=context.options[0]||{};const tempPaths=options.tempPaths||DEFAULT_TEMP_PATHS;const ignoreFiles=options.ignoreFiles||[];const filename=context.filename;if(ignoreFiles.some(pattern=>filename.includes(pattern))){return{}}function report(node){context.report({node,messageId:"violationDetected"})}return{CallExpression(node){if(node.callee.type==="MemberExpression"&&node.callee.object.type==="Identifier"&&node.callee.object.name==="fs"&&node.callee.property.type==="Identifier"&&["writeFileSync","writeFile"].includes(node.callee.property.name)){const pathArg=node.arguments[0];if(pathArg&&pathArg.type==="Literal"&&typeof pathArg.value==="string"){if(tempPaths.some(tp=>pathArg.value.includes(tp))){report(pathArg)}}}},Literal(node){if(typeof node.value==="string"){if(tempPaths.some(tp=>node.value.includes(tp))){const parent=node.parent;if(parent?.type==="VariableDeclarator"||parent?.type==="AssignmentExpression"){report(node)}}}}}}});
|
|
@@ -1,84 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noDeprecatedBuffer = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noDeprecatedBuffer = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-deprecated-buffer',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'problem',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-deprecated-buffer.md',
|
|
11
|
-
description: 'Disallow the deprecated `new Buffer()` constructor and `Buffer()` factory call.',
|
|
12
|
-
cwe: 'CWE-676',
|
|
13
|
-
cvss: 7.5,
|
|
14
|
-
},
|
|
15
|
-
fixable: 'code',
|
|
16
|
-
messages: {
|
|
17
|
-
deprecatedBufferConstructor: (0, eslint_devkit_1.formatLLMMessage)({
|
|
18
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
19
|
-
issueName: 'Deprecated Buffer Constructor',
|
|
20
|
-
cwe: 'CWE-676',
|
|
21
|
-
cvss: 7.5,
|
|
22
|
-
description: '`new Buffer()` is deprecated since Node 10 and unsafe — when called with a number it returns uninitialized memory (CVE-2018-7166).',
|
|
23
|
-
severity: 'HIGH',
|
|
24
|
-
fix: 'Use `Buffer.alloc(size)` (zero-filled), `Buffer.allocUnsafe(size)` (only when you immediately overwrite the buffer), or `Buffer.from(value)` (for strings/arrays/buffers).',
|
|
25
|
-
documentationLink: 'https://nodejs.org/api/buffer.html#bufnew-buffersize',
|
|
26
|
-
}),
|
|
27
|
-
deprecatedBufferCall: (0, eslint_devkit_1.formatLLMMessage)({
|
|
28
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
29
|
-
issueName: 'Deprecated Buffer() Factory Call',
|
|
30
|
-
cwe: 'CWE-676',
|
|
31
|
-
cvss: 7.5,
|
|
32
|
-
description: '`Buffer()` (without `new`) is deprecated since Node 10 and unsafe — when called with a number it returns uninitialized memory.',
|
|
33
|
-
severity: 'HIGH',
|
|
34
|
-
fix: 'Use `Buffer.alloc(size)`, `Buffer.allocUnsafe(size)`, or `Buffer.from(value)`.',
|
|
35
|
-
documentationLink: 'https://nodejs.org/api/buffer.html#bufnew-buffersize',
|
|
36
|
-
}),
|
|
37
|
-
},
|
|
38
|
-
schema: [],
|
|
39
|
-
},
|
|
40
|
-
defaultOptions: [],
|
|
41
|
-
create(context) {
|
|
42
|
-
function isBufferIdentifier(node) {
|
|
43
|
-
return (node.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
44
|
-
node.name === 'Buffer');
|
|
45
|
-
}
|
|
46
|
-
function getBufferReplacement(args) {
|
|
47
|
-
if (args.length === 1 &&
|
|
48
|
-
args[0].type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
49
|
-
typeof args[0].value === 'number') {
|
|
50
|
-
return 'Buffer.alloc';
|
|
51
|
-
}
|
|
52
|
-
return 'Buffer.from';
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
NewExpression(node) {
|
|
56
|
-
if (!isBufferIdentifier(node.callee))
|
|
57
|
-
return;
|
|
58
|
-
const replacement = getBufferReplacement(node.arguments);
|
|
59
|
-
context.report({
|
|
60
|
-
node,
|
|
61
|
-
messageId: 'deprecatedBufferConstructor',
|
|
62
|
-
fix(fixer) {
|
|
63
|
-
const sourceCode = context.sourceCode;
|
|
64
|
-
const newToken = sourceCode.getFirstToken(node);
|
|
65
|
-
const calleeEnd = node.callee.range[1];
|
|
66
|
-
return fixer.replaceTextRange([newToken.range[0], calleeEnd], replacement);
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
},
|
|
70
|
-
CallExpression(node) {
|
|
71
|
-
if (!isBufferIdentifier(node.callee))
|
|
72
|
-
return;
|
|
73
|
-
const replacement = getBufferReplacement(node.arguments);
|
|
74
|
-
context.report({
|
|
75
|
-
node,
|
|
76
|
-
messageId: 'deprecatedBufferCall',
|
|
77
|
-
fix(fixer) {
|
|
78
|
-
return fixer.replaceText(node.callee, replacement);
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
},
|
|
84
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noDeprecatedBuffer=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noDeprecatedBuffer=(0,eslint_devkit_1.createRule)({name:"no-deprecated-buffer",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-deprecated-buffer.md",description:"Disallow the deprecated `new Buffer()` constructor and `Buffer()` factory call.",cwe:"CWE-676",cvss:7.5},fixable:"code",messages:{deprecatedBufferConstructor:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Deprecated Buffer Constructor",cwe:"CWE-676",cvss:7.5,description:"`new Buffer()` is deprecated since Node 10 and unsafe \u2014 when called with a number it returns uninitialized memory (CVE-2018-7166).",severity:"HIGH",fix:"Use `Buffer.alloc(size)` (zero-filled), `Buffer.allocUnsafe(size)` (only when you immediately overwrite the buffer), or `Buffer.from(value)` (for strings/arrays/buffers).",documentationLink:"https://nodejs.org/api/buffer.html#bufnew-buffersize"}),deprecatedBufferCall:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Deprecated Buffer() Factory Call",cwe:"CWE-676",cvss:7.5,description:"`Buffer()` (without `new`) is deprecated since Node 10 and unsafe \u2014 when called with a number it returns uninitialized memory.",severity:"HIGH",fix:"Use `Buffer.alloc(size)`, `Buffer.allocUnsafe(size)`, or `Buffer.from(value)`.",documentationLink:"https://nodejs.org/api/buffer.html#bufnew-buffersize"})},schema:[]},defaultOptions:[],create(context){function isBufferIdentifier(node){return node.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&node.name==="Buffer"}function getBufferReplacement(args){if(args.length===1&&args[0].type===eslint_devkit_1.AST_NODE_TYPES.Literal&&typeof args[0].value==="number"){return"Buffer.alloc"}return"Buffer.from"}return{NewExpression(node){if(!isBufferIdentifier(node.callee))return;const replacement=getBufferReplacement(node.arguments);context.report({node,messageId:"deprecatedBufferConstructor",fix(fixer){const sourceCode=context.sourceCode;const newToken=sourceCode.getFirstToken(node);const calleeEnd=node.callee.range[1];return fixer.replaceTextRange([newToken.range[0],calleeEnd],replacement)}})},CallExpression(node){if(!isBufferIdentifier(node.callee))return;const replacement=getBufferReplacement(node.arguments);context.report({node,messageId:"deprecatedBufferCall",fix(fixer){return fixer.replaceText(node.callee,replacement)}})}}}});
|
|
@@ -1,112 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noDeprecatedCipherMethod = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const DEPRECATED_METHODS = new Set(['createCipher', 'createDecipher']);
|
|
6
|
-
exports.noDeprecatedCipherMethod = (0, eslint_devkit_1.createRule)({
|
|
7
|
-
name: 'no-deprecated-cipher-method',
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'problem',
|
|
10
|
-
docs: {
|
|
11
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-deprecated-cipher-method.md',
|
|
12
|
-
description: 'Disallow deprecated crypto.createCipher/createDecipher methods (use createCipheriv/createDecipheriv instead)',
|
|
13
|
-
cwe: 'CWE-327',
|
|
14
|
-
cvss: 7.5,
|
|
15
|
-
},
|
|
16
|
-
hasSuggestions: true,
|
|
17
|
-
messages: {
|
|
18
|
-
deprecatedCipherMethod: (0, eslint_devkit_1.formatLLMMessage)({
|
|
19
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
20
|
-
issueName: 'Deprecated cipher method',
|
|
21
|
-
cwe: 'CWE-327',
|
|
22
|
-
description: 'crypto.{{method}}() is deprecated. It derives key from password without salt and uses no IV, making encryption deterministic and vulnerable.',
|
|
23
|
-
severity: 'HIGH',
|
|
24
|
-
fix: 'Use crypto.{{replacement}}() with explicit key and random IV',
|
|
25
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
|
|
26
|
-
}),
|
|
27
|
-
useCipheriv: (0, eslint_devkit_1.formatLLMMessage)({
|
|
28
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
29
|
-
issueName: 'Use createCipheriv',
|
|
30
|
-
description: 'Use createCipheriv with explicit key derivation and random IV',
|
|
31
|
-
severity: 'LOW',
|
|
32
|
-
fix: 'const key = crypto.scryptSync(password, salt, 32);\nconst iv = crypto.randomBytes(16);\nconst cipher = crypto.createCipheriv(algorithm, key, iv);',
|
|
33
|
-
documentationLink: 'https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options',
|
|
34
|
-
}),
|
|
35
|
-
},
|
|
36
|
-
schema: [
|
|
37
|
-
{
|
|
38
|
-
type: 'object',
|
|
39
|
-
properties: {
|
|
40
|
-
allowInTests: {
|
|
41
|
-
type: 'boolean',
|
|
42
|
-
default: false,
|
|
43
|
-
description: 'Allow deprecated methods in test files',
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
additionalProperties: false,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
defaultOptions: [
|
|
51
|
-
{
|
|
52
|
-
allowInTests: false,
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
create(context, [options = {}]) {
|
|
56
|
-
const { allowInTests = false } = options;
|
|
57
|
-
const filename = context.filename;
|
|
58
|
-
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
59
|
-
function checkCallExpression(node) {
|
|
60
|
-
if (isTestFile)
|
|
61
|
-
return;
|
|
62
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
63
|
-
node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
64
|
-
DEPRECATED_METHODS.has(node.callee.property.name)) {
|
|
65
|
-
const callee = node.callee;
|
|
66
|
-
const propertyNode = callee.property;
|
|
67
|
-
const methodName = propertyNode.name;
|
|
68
|
-
const replacementName = methodName === 'createCipher' ? 'createCipheriv' : 'createDecipheriv';
|
|
69
|
-
context.report({
|
|
70
|
-
node: propertyNode,
|
|
71
|
-
messageId: 'deprecatedCipherMethod',
|
|
72
|
-
data: {
|
|
73
|
-
method: methodName,
|
|
74
|
-
replacement: replacementName,
|
|
75
|
-
},
|
|
76
|
-
suggest: [
|
|
77
|
-
{
|
|
78
|
-
messageId: 'useCipheriv',
|
|
79
|
-
fix: (fixer) => {
|
|
80
|
-
return fixer.replaceText(propertyNode, replacementName);
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
87
|
-
DEPRECATED_METHODS.has(node.callee.name)) {
|
|
88
|
-
const methodName = node.callee.name;
|
|
89
|
-
const replacementName = methodName === 'createCipher' ? 'createCipheriv' : 'createDecipheriv';
|
|
90
|
-
context.report({
|
|
91
|
-
node: node.callee,
|
|
92
|
-
messageId: 'deprecatedCipherMethod',
|
|
93
|
-
data: {
|
|
94
|
-
method: methodName,
|
|
95
|
-
replacement: replacementName,
|
|
96
|
-
},
|
|
97
|
-
suggest: [
|
|
98
|
-
{
|
|
99
|
-
messageId: 'useCipheriv',
|
|
100
|
-
fix: (fixer) => {
|
|
101
|
-
return fixer.replaceText(node.callee, replacementName);
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
CallExpression: checkCallExpression,
|
|
110
|
-
};
|
|
111
|
-
},
|
|
112
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noDeprecatedCipherMethod=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const DEPRECATED_METHODS=new Set(["createCipher","createDecipher"]);exports.noDeprecatedCipherMethod=(0,eslint_devkit_1.createRule)({name:"no-deprecated-cipher-method",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-deprecated-cipher-method.md",description:"Disallow deprecated crypto.createCipher/createDecipher methods (use createCipheriv/createDecipheriv instead)",cwe:"CWE-327",cvss:7.5},hasSuggestions:true,messages:{deprecatedCipherMethod:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Deprecated cipher method",cwe:"CWE-327",description:"crypto.{{method}}() is deprecated. It derives key from password without salt and uses no IV, making encryption deterministic and vulnerable.",severity:"HIGH",fix:"Use crypto.{{replacement}}() with explicit key and random IV",documentationLink:"https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options"}),useCipheriv:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use createCipheriv",description:"Use createCipheriv with explicit key derivation and random IV",severity:"LOW",fix:"const key = crypto.scryptSync(password, salt, 32);\nconst iv = crypto.randomBytes(16);\nconst cipher = crypto.createCipheriv(algorithm, key, iv);",documentationLink:"https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options"})},schema:[{type:"object",properties:{allowInTests:{type:"boolean",default:false,description:"Allow deprecated methods in test files"}},additionalProperties:false}]},defaultOptions:[{allowInTests:false}],create(context,[options={}]){const{allowInTests=false}=options;const filename=context.filename;const isTestFile=allowInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);function checkCallExpression(node){if(isTestFile)return;if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression&&node.callee.property.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&DEPRECATED_METHODS.has(node.callee.property.name)){const callee=node.callee;const propertyNode=callee.property;const methodName=propertyNode.name;const replacementName=methodName==="createCipher"?"createCipheriv":"createDecipheriv";context.report({node:propertyNode,messageId:"deprecatedCipherMethod",data:{method:methodName,replacement:replacementName},suggest:[{messageId:"useCipheriv",fix:fixer=>{return fixer.replaceText(propertyNode,replacementName)}}]})}if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&DEPRECATED_METHODS.has(node.callee.name)){const methodName=node.callee.name;const replacementName=methodName==="createCipher"?"createCipheriv":"createDecipheriv";context.report({node:node.callee,messageId:"deprecatedCipherMethod",data:{method:methodName,replacement:replacementName},suggest:[{messageId:"useCipheriv",fix:fixer=>{return fixer.replaceText(node.callee,replacementName)}}]})}}return{CallExpression:checkCallExpression}}});
|
|
@@ -1,72 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noDynamicAlgorithmSelection = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const CRYPTO_ALGORITHM_FUNCTIONS = new Set([
|
|
6
|
-
'createHash',
|
|
7
|
-
'createHmac',
|
|
8
|
-
'createSign',
|
|
9
|
-
'createVerify',
|
|
10
|
-
'createCipher',
|
|
11
|
-
'createCipheriv',
|
|
12
|
-
'createDecipher',
|
|
13
|
-
'createDecipheriv',
|
|
14
|
-
]);
|
|
15
|
-
exports.noDynamicAlgorithmSelection = (0, eslint_devkit_1.createRule)({
|
|
16
|
-
name: 'no-dynamic-algorithm-selection',
|
|
17
|
-
meta: {
|
|
18
|
-
type: 'problem',
|
|
19
|
-
docs: {
|
|
20
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-dynamic-algorithm-selection.md',
|
|
21
|
-
description: 'Disallow dynamic algorithm names in Node.js crypto functions (CWE-327)',
|
|
22
|
-
cwe: 'CWE-327',
|
|
23
|
-
cvss: 7.5,
|
|
24
|
-
},
|
|
25
|
-
messages: {
|
|
26
|
-
dynamicAlgorithm: (0, eslint_devkit_1.formatLLMMessage)({
|
|
27
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
28
|
-
issueName: 'Dynamic Cryptographic Algorithm (CWE-327)',
|
|
29
|
-
cwe: 'CWE-327',
|
|
30
|
-
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.',
|
|
31
|
-
severity: 'HIGH',
|
|
32
|
-
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.',
|
|
33
|
-
documentationLink: 'https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html',
|
|
34
|
-
}),
|
|
35
|
-
},
|
|
36
|
-
schema: [],
|
|
37
|
-
},
|
|
38
|
-
defaultOptions: [],
|
|
39
|
-
create(context) {
|
|
40
|
-
return {
|
|
41
|
-
CallExpression(node) {
|
|
42
|
-
const { callee, arguments: args } = node;
|
|
43
|
-
if (callee.type !== eslint_devkit_1.AST_NODE_TYPES.MemberExpression)
|
|
44
|
-
return;
|
|
45
|
-
if (callee.object.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier)
|
|
46
|
-
return;
|
|
47
|
-
if (callee.property.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier)
|
|
48
|
-
return;
|
|
49
|
-
const objectName = callee.object.name;
|
|
50
|
-
const methodName = callee.property.name;
|
|
51
|
-
if (objectName !== 'crypto')
|
|
52
|
-
return;
|
|
53
|
-
if (!CRYPTO_ALGORITHM_FUNCTIONS.has(methodName))
|
|
54
|
-
return;
|
|
55
|
-
const firstArg = args[0];
|
|
56
|
-
if (!firstArg)
|
|
57
|
-
return;
|
|
58
|
-
if (firstArg.type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
59
|
-
typeof firstArg.value === 'string')
|
|
60
|
-
return;
|
|
61
|
-
if (firstArg.type === eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral &&
|
|
62
|
-
firstArg.expressions.length === 0)
|
|
63
|
-
return;
|
|
64
|
-
context.report({
|
|
65
|
-
node: firstArg,
|
|
66
|
-
messageId: 'dynamicAlgorithm',
|
|
67
|
-
data: { method: methodName },
|
|
68
|
-
});
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noDynamicAlgorithmSelection=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const CRYPTO_ALGORITHM_FUNCTIONS=new Set(["createHash","createHmac","createSign","createVerify","createCipher","createCipheriv","createDecipher","createDecipheriv"]);exports.noDynamicAlgorithmSelection=(0,eslint_devkit_1.createRule)({name:"no-dynamic-algorithm-selection",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-dynamic-algorithm-selection.md",description:"Disallow dynamic algorithm names in Node.js crypto functions (CWE-327)",cwe:"CWE-327",cvss:7.5},messages:{dynamicAlgorithm:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Dynamic Cryptographic Algorithm (CWE-327)",cwe:"CWE-327",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.",severity:"HIGH",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.',documentationLink:"https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html"})},schema:[]},defaultOptions:[],create(context){return{CallExpression(node){const{callee,arguments:args}=node;if(callee.type!==eslint_devkit_1.AST_NODE_TYPES.MemberExpression)return;if(callee.object.type!==eslint_devkit_1.AST_NODE_TYPES.Identifier)return;if(callee.property.type!==eslint_devkit_1.AST_NODE_TYPES.Identifier)return;const objectName=callee.object.name;const methodName=callee.property.name;if(objectName!=="crypto")return;if(!CRYPTO_ALGORITHM_FUNCTIONS.has(methodName))return;const firstArg=args[0];if(!firstArg)return;if(firstArg.type===eslint_devkit_1.AST_NODE_TYPES.Literal&&typeof firstArg.value==="string")return;if(firstArg.type===eslint_devkit_1.AST_NODE_TYPES.TemplateLiteral&&firstArg.expressions.length===0)return;context.report({node:firstArg,messageId:"dynamicAlgorithm",data:{method:methodName}})}}}});
|