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,152 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noArbitraryFileAccess = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noArbitraryFileAccess = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-arbitrary-file-access',
|
|
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-arbitrary-file-access.md',
|
|
11
|
-
description: 'Prevent file access from user input',
|
|
12
|
-
cwe: 'CWE-22',
|
|
13
|
-
cvss: 7.5,
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
18
|
-
issueName: 'Arbitrary File Access',
|
|
19
|
-
cwe: 'CWE-22',
|
|
20
|
-
description: 'File path from user input - path traversal vulnerability',
|
|
21
|
-
severity: 'HIGH',
|
|
22
|
-
fix: 'Validate and sanitize file paths, use allowlists',
|
|
23
|
-
documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
|
|
24
|
-
})
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
const sourceCode = context.sourceCode;
|
|
31
|
-
function report(node) {
|
|
32
|
-
context.report({ node, messageId: 'violationDetected' });
|
|
33
|
-
}
|
|
34
|
-
const fsReadMethods = ['readFile', 'readFileSync', 'readdir', 'readdirSync', 'stat', 'statSync'];
|
|
35
|
-
const fsWriteMethods = ['writeFile', 'writeFileSync', 'appendFile', 'appendFileSync'];
|
|
36
|
-
const userInputSources = new Set(['req', 'request', 'params', 'query', 'body']);
|
|
37
|
-
const sanitizedVariables = new Set();
|
|
38
|
-
const validatedVariables = new Set();
|
|
39
|
-
function checkVariableDeclaration(node) {
|
|
40
|
-
if (node.id.type !== 'Identifier' || !node.init) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const varName = node.id.name;
|
|
44
|
-
const init = node.init;
|
|
45
|
-
if (init.type === 'CallExpression' &&
|
|
46
|
-
init.callee.type === 'MemberExpression' &&
|
|
47
|
-
init.callee.object.type === 'Identifier' &&
|
|
48
|
-
init.callee.object.name === 'path' &&
|
|
49
|
-
init.callee.property.type === 'Identifier' &&
|
|
50
|
-
init.callee.property.name === 'basename') {
|
|
51
|
-
sanitizedVariables.add(varName);
|
|
52
|
-
}
|
|
53
|
-
if (init.type === 'CallExpression' &&
|
|
54
|
-
init.callee.type === 'MemberExpression' &&
|
|
55
|
-
init.callee.object.type === 'Identifier' &&
|
|
56
|
-
init.callee.object.name === 'path' &&
|
|
57
|
-
init.callee.property.type === 'Identifier' &&
|
|
58
|
-
init.callee.property.name === 'join') {
|
|
59
|
-
const hasSanitizedArg = init.arguments.some((arg) => arg.type === 'Identifier' && sanitizedVariables.has(arg.name));
|
|
60
|
-
const firstArg = init.arguments[0];
|
|
61
|
-
const hasSafeBase = firstArg && (firstArg.type === 'Literal' ||
|
|
62
|
-
(firstArg.type === 'Identifier' && /^(SAFE|BASE|ROOT|UPLOAD|PUBLIC)/i.test(firstArg.name)));
|
|
63
|
-
if (hasSanitizedArg && hasSafeBase) {
|
|
64
|
-
sanitizedVariables.add(varName);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function hasStartsWithGuard(node, varName) {
|
|
69
|
-
if (validatedVariables.has(varName)) {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
let current = node.parent;
|
|
73
|
-
while (current) {
|
|
74
|
-
if (current.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement) {
|
|
75
|
-
const statements = current.body;
|
|
76
|
-
for (const stmt of statements) {
|
|
77
|
-
if (stmt.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
|
|
78
|
-
const testText = sourceCode.getText(stmt.test).toLowerCase();
|
|
79
|
-
if (testText.includes('startswith') && testText.includes(varName.toLowerCase())) {
|
|
80
|
-
const consequent = stmt.consequent;
|
|
81
|
-
if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement && consequent.body.length > 0) {
|
|
82
|
-
const firstStmt = consequent.body[0];
|
|
83
|
-
if (firstStmt.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement || firstStmt.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement) {
|
|
84
|
-
validatedVariables.add(varName);
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement || consequent.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement) {
|
|
89
|
-
validatedVariables.add(varName);
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (current.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
|
|
97
|
-
const testText = sourceCode.getText(current.test).toLowerCase();
|
|
98
|
-
if (testText.includes('startswith') && testText.includes(varName.toLowerCase())) {
|
|
99
|
-
validatedVariables.add(varName);
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
current = current.parent;
|
|
104
|
-
}
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
function isVariableSafe(varName, node) {
|
|
108
|
-
if (sanitizedVariables.has(varName)) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
if (hasStartsWithGuard(node, varName)) {
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
if (/^(safe|sanitized|validated|clean)/i.test(varName)) {
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
VariableDeclarator(node) {
|
|
121
|
-
checkVariableDeclaration(node);
|
|
122
|
-
},
|
|
123
|
-
CallExpression(node) {
|
|
124
|
-
if (node.callee.type === 'MemberExpression' &&
|
|
125
|
-
node.callee.object.type === 'Identifier' &&
|
|
126
|
-
node.callee.object.name === 'fs' &&
|
|
127
|
-
node.callee.property.type === 'Identifier' &&
|
|
128
|
-
[...fsReadMethods, ...fsWriteMethods].includes(node.callee.property.name)) {
|
|
129
|
-
const pathArg = node.arguments[0];
|
|
130
|
-
if (pathArg && pathArg.type === 'Literal') {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (pathArg && pathArg.type === 'Identifier') {
|
|
134
|
-
const varName = pathArg.name;
|
|
135
|
-
if (isVariableSafe(varName, node)) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
report(node);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (pathArg?.type === 'MemberExpression' &&
|
|
142
|
-
pathArg.object.type === 'Identifier') {
|
|
143
|
-
const objName = pathArg.object.name.toLowerCase();
|
|
144
|
-
if (userInputSources.has(objName)) {
|
|
145
|
-
report(node);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
},
|
|
152
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noArbitraryFileAccess=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noArbitraryFileAccess=(0,eslint_devkit_1.createRule)({name:"no-arbitrary-file-access",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-node-security/docs/rules/no-arbitrary-file-access.md",description:"Prevent file access from user input",cwe:"CWE-22",cvss:7.5},messages:{violationDetected:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Arbitrary File Access",cwe:"CWE-22",description:"File path from user input - path traversal vulnerability",severity:"HIGH",fix:"Validate and sanitize file paths, use allowlists",documentationLink:"https://cwe.mitre.org/data/definitions/22.html"})},schema:[]},defaultOptions:[],create(context){const sourceCode=context.sourceCode;function report(node){context.report({node,messageId:"violationDetected"})}const fsReadMethods=["readFile","readFileSync","readdir","readdirSync","stat","statSync"];const fsWriteMethods=["writeFile","writeFileSync","appendFile","appendFileSync"];const userInputSources=new Set(["req","request","params","query","body"]);const sanitizedVariables=new Set;const validatedVariables=new Set;function checkVariableDeclaration(node){if(node.id.type!=="Identifier"||!node.init){return}const varName=node.id.name;const init=node.init;if(init.type==="CallExpression"&&init.callee.type==="MemberExpression"&&init.callee.object.type==="Identifier"&&init.callee.object.name==="path"&&init.callee.property.type==="Identifier"&&init.callee.property.name==="basename"){sanitizedVariables.add(varName)}if(init.type==="CallExpression"&&init.callee.type==="MemberExpression"&&init.callee.object.type==="Identifier"&&init.callee.object.name==="path"&&init.callee.property.type==="Identifier"&&init.callee.property.name==="join"){const hasSanitizedArg=init.arguments.some(arg=>arg.type==="Identifier"&&sanitizedVariables.has(arg.name));const firstArg=init.arguments[0];const hasSafeBase=firstArg&&(firstArg.type==="Literal"||firstArg.type==="Identifier"&&/^(SAFE|BASE|ROOT|UPLOAD|PUBLIC)/i.test(firstArg.name));if(hasSanitizedArg&&hasSafeBase){sanitizedVariables.add(varName)}}}function hasStartsWithGuard(node,varName){if(validatedVariables.has(varName)){return true}let current=node.parent;while(current){if(current.type===eslint_devkit_1.AST_NODE_TYPES.BlockStatement){const statements=current.body;for(const stmt of statements){if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.IfStatement){const testText=sourceCode.getText(stmt.test).toLowerCase();if(testText.includes("startswith")&&testText.includes(varName.toLowerCase())){const consequent=stmt.consequent;if(consequent.type===eslint_devkit_1.AST_NODE_TYPES.BlockStatement&&consequent.body.length>0){const firstStmt=consequent.body[0];if(firstStmt.type===eslint_devkit_1.AST_NODE_TYPES.ThrowStatement||firstStmt.type===eslint_devkit_1.AST_NODE_TYPES.ReturnStatement){validatedVariables.add(varName);return true}}if(consequent.type===eslint_devkit_1.AST_NODE_TYPES.ThrowStatement||consequent.type===eslint_devkit_1.AST_NODE_TYPES.ReturnStatement){validatedVariables.add(varName);return true}}}}}if(current.type===eslint_devkit_1.AST_NODE_TYPES.IfStatement){const testText=sourceCode.getText(current.test).toLowerCase();if(testText.includes("startswith")&&testText.includes(varName.toLowerCase())){validatedVariables.add(varName);return true}}current=current.parent}return false}function isVariableSafe(varName,node){if(sanitizedVariables.has(varName)){return true}if(hasStartsWithGuard(node,varName)){return true}if(/^(safe|sanitized|validated|clean)/i.test(varName)){return true}return false}return{VariableDeclarator(node){checkVariableDeclaration(node)},CallExpression(node){if(node.callee.type==="MemberExpression"&&node.callee.object.type==="Identifier"&&node.callee.object.name==="fs"&&node.callee.property.type==="Identifier"&&[...fsReadMethods,...fsWriteMethods].includes(node.callee.property.name)){const pathArg=node.arguments[0];if(pathArg&&pathArg.type==="Literal"){return}if(pathArg&&pathArg.type==="Identifier"){const varName=pathArg.name;if(isVariableSafe(varName,node)){return}report(node);return}if(pathArg?.type==="MemberExpression"&&pathArg.object.type==="Identifier"){const objName=pathArg.object.name.toLowerCase();if(userInputSources.has(objName)){report(node)}}}}}}});
|