eslint-plugin-security 1.4.0 → 1.6.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/.eslint-doc-generatorrc.js +9 -0
- package/.eslintrc +29 -1
- package/.github/ISSUE_TEMPLATE/bug-report.yml +85 -0
- package/.github/ISSUE_TEMPLATE/new-rule.yml +39 -0
- package/.github/ISSUE_TEMPLATE/rule-change.yml +61 -0
- package/.github/workflows/ci.yml +55 -0
- package/.github/workflows/pr.yml +19 -0
- package/.github/workflows/release-please.yml +39 -0
- package/.markdownlint.json +4 -0
- package/.markdownlintignore +3 -0
- package/.prettierrc.json +7 -0
- package/CHANGELOG.md +114 -34
- package/README.md +45 -85
- package/docs/avoid-command-injection-node.md +85 -0
- package/docs/bypass-connect-csrf-protection-by-abusing.md +42 -0
- package/docs/regular-expression-dos-and-node.md +83 -0
- package/docs/rules/detect-bidi-characters.md +50 -0
- package/docs/rules/detect-buffer-noassert.md +9 -0
- package/docs/rules/detect-child-process.md +9 -0
- package/docs/rules/detect-disable-mustache-escape.md +9 -0
- package/docs/rules/detect-eval-with-expression.md +7 -0
- package/docs/rules/detect-new-buffer.md +5 -0
- package/docs/rules/detect-no-csrf-before-method-override.md +9 -0
- package/docs/rules/detect-non-literal-fs-filename.md +7 -0
- package/docs/rules/detect-non-literal-regexp.md +7 -0
- package/docs/rules/detect-non-literal-require.md +7 -0
- package/docs/rules/detect-object-injection.md +7 -0
- package/docs/rules/detect-possible-timing-attacks.md +5 -0
- package/docs/rules/detect-pseudoRandomBytes.md +5 -0
- package/docs/rules/detect-unsafe-regex.md +7 -0
- package/docs/the-dangers-of-square-bracket-notation.md +107 -0
- package/index.js +10 -9
- package/package.json +34 -7
- package/rules/detect-bidi-characters.js +101 -0
- package/rules/detect-buffer-noassert.js +66 -55
- package/rules/detect-child-process.js +57 -25
- package/rules/detect-disable-mustache-escape.js +24 -14
- package/rules/detect-eval-with-expression.js +19 -9
- package/rules/detect-new-buffer.js +19 -16
- package/rules/detect-no-csrf-before-method-override.js +32 -25
- package/rules/detect-non-literal-fs-filename.js +86 -33
- package/rules/detect-non-literal-regexp.js +24 -18
- package/rules/detect-non-literal-require.js +25 -17
- package/rules/detect-object-injection.js +61 -59
- package/rules/detect-possible-timing-attacks.js +40 -42
- package/rules/detect-pseudoRandomBytes.js +18 -11
- package/rules/detect-unsafe-regex.js +36 -23
- package/test/detect-bidi-characters.js +74 -0
- package/test/detect-buffer-noassert.js +18 -18
- package/test/detect-child-process.js +49 -23
- package/test/detect-disable-mustache-escape.js +3 -4
- package/test/detect-eval-with-expression.js +4 -5
- package/test/detect-new-buffer.js +4 -5
- package/test/detect-no-csrf-before-method-override.js +3 -4
- package/test/detect-non-literal-fs-filename.js +135 -9
- package/test/detect-non-literal-regexp.js +5 -6
- package/test/detect-non-literal-require.js +11 -8
- package/test/detect-object-injection.js +3 -5
- package/test/detect-possible-timing-attacks.js +8 -10
- package/test/detect-pseudoRandomBytes.js +3 -4
- package/test/detect-unsafe-regexp.js +9 -11
- package/test/utils/import-utils.js +172 -0
- package/utils/data/fsFunctionData.json +51 -0
- package/utils/import-utils.js +196 -0
- package/.npmignore +0 -1
- package/rules/data/fsFunctionData.json +0 -51
package/index.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = {
|
|
|
18
18
|
'detect-child-process': require('./rules/detect-child-process'),
|
|
19
19
|
'detect-disable-mustache-escape': require('./rules/detect-disable-mustache-escape'),
|
|
20
20
|
'detect-object-injection': require('./rules/detect-object-injection'),
|
|
21
|
-
'detect-new-buffer': require('./rules/detect-new-buffer')
|
|
21
|
+
'detect-new-buffer': require('./rules/detect-new-buffer'),
|
|
22
|
+
'detect-bidi-characters': require('./rules/detect-bidi-characters'),
|
|
22
23
|
},
|
|
23
24
|
rulesConfig: {
|
|
24
25
|
'detect-unsafe-regex': 0,
|
|
@@ -33,13 +34,12 @@ module.exports = {
|
|
|
33
34
|
'detect-child-process': 0,
|
|
34
35
|
'detect-disable-mustache-escape': 0,
|
|
35
36
|
'detect-object-injection': 0,
|
|
36
|
-
'detect-new-buffer': 0
|
|
37
|
+
'detect-new-buffer': 0,
|
|
38
|
+
'detect-bidi-characters': 0,
|
|
37
39
|
},
|
|
38
40
|
configs: {
|
|
39
41
|
recommended: {
|
|
40
|
-
plugins: [
|
|
41
|
-
'security'
|
|
42
|
-
],
|
|
42
|
+
plugins: ['security'],
|
|
43
43
|
rules: {
|
|
44
44
|
'security/detect-buffer-noassert': 'warn',
|
|
45
45
|
'security/detect-child-process': 'warn',
|
|
@@ -53,8 +53,9 @@ module.exports = {
|
|
|
53
53
|
'security/detect-object-injection': 'warn',
|
|
54
54
|
'security/detect-possible-timing-attacks': 'warn',
|
|
55
55
|
'security/detect-pseudoRandomBytes': 'warn',
|
|
56
|
-
'security/detect-unsafe-regex': 'warn'
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
'security/detect-unsafe-regex': 'warn',
|
|
57
|
+
'security/detect-bidi-characters': 'warn',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
60
61
|
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-security",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Security rules for eslint",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"changelog": "changelog eslint-plugin-security all > CHANGELOG.md",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
8
|
+
"cont-int": "npm test && npm run lint",
|
|
9
|
+
"format": "prettier --write .",
|
|
10
|
+
"lint": "npm-run-all \"lint:*\"",
|
|
11
|
+
"lint:docs": "markdownlint \"**/*.md\"",
|
|
12
|
+
"lint:eslint-docs": "npm run update:eslint-docs -- --check",
|
|
13
|
+
"lint:js": "eslint .",
|
|
14
|
+
"lint:js:fix": "npm run lint:js -- --fix",
|
|
15
|
+
"release": "npx semantic-release",
|
|
16
|
+
"test": "mocha test/**",
|
|
17
|
+
"update:eslint-docs": "eslint-doc-generator"
|
|
11
18
|
},
|
|
12
19
|
"repository": {
|
|
13
20
|
"type": "git",
|
|
@@ -24,13 +31,33 @@
|
|
|
24
31
|
"url": "https://github.com/nodesecurity/eslint-plugin-security/issues"
|
|
25
32
|
},
|
|
26
33
|
"homepage": "https://github.com/nodesecurity/eslint-plugin-security#readme",
|
|
34
|
+
"gitHooks": {
|
|
35
|
+
"pre-commit": "lint-staged"
|
|
36
|
+
},
|
|
37
|
+
"lint-staged": {
|
|
38
|
+
"*.js": [
|
|
39
|
+
"prettier --write",
|
|
40
|
+
"eslint --fix"
|
|
41
|
+
],
|
|
42
|
+
"*.md": "prettier --write",
|
|
43
|
+
"*.yml": "prettier --write"
|
|
44
|
+
},
|
|
27
45
|
"dependencies": {
|
|
28
|
-
"safe-regex": "^1.1
|
|
46
|
+
"safe-regex": "^2.1.1"
|
|
29
47
|
},
|
|
30
48
|
"devDependencies": {
|
|
31
49
|
"changelog": "1.3.0",
|
|
32
|
-
"eslint": "^
|
|
50
|
+
"eslint": "^8.11.0",
|
|
33
51
|
"eslint-config-nodesecurity": "^1.3.1",
|
|
34
|
-
"
|
|
52
|
+
"eslint-config-prettier": "^8.5.0",
|
|
53
|
+
"eslint-doc-generator": "^1.0.2",
|
|
54
|
+
"eslint-plugin-eslint-plugin": "^5.0.2",
|
|
55
|
+
"lint-staged": "^12.3.7",
|
|
56
|
+
"markdownlint-cli": "^0.32.2",
|
|
57
|
+
"mocha": "^9.2.2",
|
|
58
|
+
"npm-run-all": "^4.1.5",
|
|
59
|
+
"prettier": "^2.6.2",
|
|
60
|
+
"semantic-release": "^19.0.2",
|
|
61
|
+
"yorkie": "^2.0.0"
|
|
35
62
|
}
|
|
36
63
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect trojan source attacks that employ unicode bidi attacks to inject malicious code
|
|
3
|
+
* @author Luciamo Mammino
|
|
4
|
+
* @author Simone Sanfratello
|
|
5
|
+
* @author Liran Tal
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const dangerousBidiCharsRegexp = /[\u061C\u200E\u200F\u202A\u202B\u202C\u202D\u202E\u2066\u2067\u2068\u2069]/gu;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detects all the dangerous bidi characters in a given source text
|
|
14
|
+
*
|
|
15
|
+
* @param {object} options - Options
|
|
16
|
+
* @param {string} options.sourceText - The source text to search for dangerous bidi characters
|
|
17
|
+
* @param {number} options.firstLineOffset - The offset of the first line in the source text
|
|
18
|
+
* @returns {Array<{line: number, column: number}>} - An array of reports, each report is an
|
|
19
|
+
* object with the line and column of the dangerous character
|
|
20
|
+
*/
|
|
21
|
+
function detectBidiCharacters({ sourceText, firstLineOffset }) {
|
|
22
|
+
const sourceTextToSearch = sourceText.toString();
|
|
23
|
+
|
|
24
|
+
const lines = sourceTextToSearch.split(/\r?\n/);
|
|
25
|
+
|
|
26
|
+
return lines.reduce((reports, line, lineIndex) => {
|
|
27
|
+
let match;
|
|
28
|
+
let offset = lineIndex == 0 ? firstLineOffset : 0;
|
|
29
|
+
|
|
30
|
+
while ((match = dangerousBidiCharsRegexp.exec(line)) !== null) {
|
|
31
|
+
reports.push({ line: lineIndex, column: offset + match.index });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return reports;
|
|
35
|
+
}, []);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function report({ context, node, tokens, message, firstLineOffset }) {
|
|
39
|
+
if (!tokens || !Array.isArray(tokens)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
tokens.forEach((token) => {
|
|
43
|
+
const reports = detectBidiCharacters({ sourceText: token.value, firstLineOffset: token.loc.start.column + firstLineOffset });
|
|
44
|
+
|
|
45
|
+
reports.forEach((report) => {
|
|
46
|
+
context.report({
|
|
47
|
+
node: node,
|
|
48
|
+
data: {
|
|
49
|
+
text: token.value,
|
|
50
|
+
},
|
|
51
|
+
loc: {
|
|
52
|
+
start: {
|
|
53
|
+
line: token.loc.start.line + report.line,
|
|
54
|
+
column: report.column,
|
|
55
|
+
},
|
|
56
|
+
end: {
|
|
57
|
+
line: token.loc.start.line + report.line,
|
|
58
|
+
column: report.column + 1,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
message,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//------------------------------------------------------------------------------
|
|
68
|
+
// Rule Definition
|
|
69
|
+
//------------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
meta: {
|
|
73
|
+
type: 'error',
|
|
74
|
+
docs: {
|
|
75
|
+
description: 'Detects trojan source attacks that employ unicode bidi attacks to inject malicious code.',
|
|
76
|
+
category: 'Possible Security Vulnerability',
|
|
77
|
+
recommended: true,
|
|
78
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-bidi-characters.md',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
create: function (context) {
|
|
82
|
+
return {
|
|
83
|
+
Program: function (node) {
|
|
84
|
+
report({
|
|
85
|
+
context,
|
|
86
|
+
node,
|
|
87
|
+
tokens: node.tokens,
|
|
88
|
+
firstLineOffset: 0,
|
|
89
|
+
message: "Detected potential trojan source attack with unicode bidi introduced in this code: '{{text}}'.",
|
|
90
|
+
});
|
|
91
|
+
report({
|
|
92
|
+
context,
|
|
93
|
+
node,
|
|
94
|
+
tokens: node.comments,
|
|
95
|
+
firstLineOffset: 2,
|
|
96
|
+
message: "Detected potential trojan source attack with unicode bidi introduced in this comment: '{{text}}'.",
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -1,69 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tries to detect buffer read / write calls that use noAssert set to true
|
|
3
|
-
* @author Adam Baldwin
|
|
3
|
+
* @author Adam Baldwin
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
// Rule Definition
|
|
8
|
-
//------------------------------------------------------------------------------
|
|
6
|
+
'use strict';
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
//-----------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
//-----------------------------------------------------------------------------
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const read = [
|
|
13
|
+
'readUInt8',
|
|
14
|
+
'readUInt16LE',
|
|
15
|
+
'readUInt16BE',
|
|
16
|
+
'readUInt32LE',
|
|
17
|
+
'readUInt32BE',
|
|
18
|
+
'readInt8',
|
|
19
|
+
'readInt16LE',
|
|
20
|
+
'readInt16BE',
|
|
21
|
+
'readInt32LE',
|
|
22
|
+
'readInt32BE',
|
|
23
|
+
'readFloatLE',
|
|
24
|
+
'readFloatBE',
|
|
25
|
+
'readDoubleLE',
|
|
26
|
+
'readDoubleBE',
|
|
27
|
+
];
|
|
13
28
|
|
|
14
|
-
|
|
29
|
+
const write = [
|
|
30
|
+
'writeUInt8',
|
|
31
|
+
'writeUInt16LE',
|
|
32
|
+
'writeUInt16BE',
|
|
33
|
+
'writeUInt32LE',
|
|
34
|
+
'writeUInt32BE',
|
|
35
|
+
'writeInt8',
|
|
36
|
+
'writeInt16LE',
|
|
37
|
+
'writeInt16BE',
|
|
38
|
+
'writeInt32LE',
|
|
39
|
+
'writeInt32BE',
|
|
40
|
+
'writeFloatLE',
|
|
41
|
+
'writeFloatBE',
|
|
42
|
+
'writeDoubleLE',
|
|
43
|
+
'writeDoubleBE',
|
|
44
|
+
];
|
|
15
45
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"readUInt16BE",
|
|
20
|
-
"readUInt32LE",
|
|
21
|
-
"readUInt32BE",
|
|
22
|
-
"readInt8",
|
|
23
|
-
"readInt16LE",
|
|
24
|
-
"readInt16BE",
|
|
25
|
-
"readInt32LE",
|
|
26
|
-
"readInt32BE",
|
|
27
|
-
"readFloatLE",
|
|
28
|
-
"readFloatBE",
|
|
29
|
-
"readDoubleL",
|
|
30
|
-
"readDoubleBE"
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
var write = [
|
|
34
|
-
"writeUInt8",
|
|
35
|
-
"writeUInt16LE",
|
|
36
|
-
"writeUInt16BE",
|
|
37
|
-
"writeUInt32LE",
|
|
38
|
-
"writeUInt32BE",
|
|
39
|
-
"writeInt8",
|
|
40
|
-
"writeInt16LE",
|
|
41
|
-
"writeInt16BE",
|
|
42
|
-
"writeInt32LE",
|
|
43
|
-
"writeInt32BE",
|
|
44
|
-
"writeFloatLE",
|
|
45
|
-
"writeFloatBE",
|
|
46
|
-
"writeDoubleLE",
|
|
47
|
-
"writeDoubleBE"
|
|
48
|
-
];
|
|
46
|
+
//------------------------------------------------------------------------------
|
|
47
|
+
// Rule Definition
|
|
48
|
+
//------------------------------------------------------------------------------
|
|
49
49
|
|
|
50
|
+
module.exports = {
|
|
51
|
+
meta: {
|
|
52
|
+
type: 'error',
|
|
53
|
+
docs: {
|
|
54
|
+
description: 'Detects calls to "buffer" with "noAssert" flag set.',
|
|
55
|
+
category: 'Possible Security Vulnerability',
|
|
56
|
+
recommended: true,
|
|
57
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-buffer-noassert.md',
|
|
58
|
+
},
|
|
59
|
+
__methodsToCheck: {
|
|
60
|
+
read,
|
|
61
|
+
write,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
create: function (context) {
|
|
50
65
|
return {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
|
|
60
|
-
var token = context.getTokens(node)[0];
|
|
61
|
-
return context.report(node, 'Found Buffer.' + node.property.name + ' with noAssert flag set true');
|
|
62
|
-
|
|
63
|
-
}
|
|
66
|
+
MemberExpression: function (node) {
|
|
67
|
+
let index;
|
|
68
|
+
if (read.indexOf(node.property.name) !== -1) {
|
|
69
|
+
index = 1;
|
|
70
|
+
} else if (write.indexOf(node.property.name) !== -1) {
|
|
71
|
+
index = 2;
|
|
64
72
|
}
|
|
65
73
|
|
|
74
|
+
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
|
|
75
|
+
return context.report({ node: node, message: `Found Buffer.${node.property.name} with noAssert flag set true` });
|
|
76
|
+
}
|
|
77
|
+
},
|
|
66
78
|
};
|
|
67
|
-
|
|
79
|
+
},
|
|
68
80
|
};
|
|
69
|
-
|
|
@@ -3,40 +3,72 @@
|
|
|
3
3
|
* @author Adam Baldwin
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
6
8
|
//------------------------------------------------------------------------------
|
|
7
9
|
// Rule Definition
|
|
8
10
|
//------------------------------------------------------------------------------
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
module.exports = {
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'error',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Detects instances of "child_process" & non-literal "exec()" calls.',
|
|
17
|
+
category: 'Possible Security Vulnerability',
|
|
18
|
+
recommended: true,
|
|
19
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-child-process.md',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
create: function (context) {
|
|
23
|
+
/*
|
|
24
|
+
* Stores variable identifiers pointing to child_process to check (child_process).exec()
|
|
25
|
+
*/
|
|
26
|
+
const childProcessIdentifiers = new Set();
|
|
13
27
|
|
|
14
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Extract identifiers assigned the expression `require("child_process")`.
|
|
30
|
+
* @param {Pattern} node
|
|
31
|
+
*/
|
|
32
|
+
function extractChildProcessIdentifiers(node) {
|
|
33
|
+
if (node.type !== 'Identifier') {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const variable = context.getScope().set.get(node.name);
|
|
37
|
+
if (!variable) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const reference of variable.references) {
|
|
41
|
+
childProcessIdentifiers.add(reference.identifier);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
15
44
|
|
|
16
45
|
return {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
CallExpression: function (node) {
|
|
47
|
+
if (node.callee.name === 'require') {
|
|
48
|
+
const args = node.arguments[0];
|
|
49
|
+
if (args && args.type === 'Literal' && args.value === 'child_process') {
|
|
50
|
+
let pattern;
|
|
51
|
+
if (node.parent.type === 'VariableDeclarator') {
|
|
52
|
+
pattern = node.parent.id;
|
|
53
|
+
} else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
|
|
54
|
+
pattern = node.parent.left;
|
|
55
|
+
}
|
|
56
|
+
if (pattern) {
|
|
57
|
+
extractChildProcessIdentifiers(pattern);
|
|
29
58
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
var token = context.getTokens(node)[0];
|
|
33
|
-
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
|
|
34
|
-
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
|
|
35
|
-
return context.report(node, 'Found child_process.exec() with non Literal first argument');
|
|
36
|
-
}
|
|
59
|
+
if (!pattern || pattern.type === 'Identifier') {
|
|
60
|
+
return context.report({ node: node, message: 'Found require("child_process")' });
|
|
37
61
|
}
|
|
62
|
+
}
|
|
38
63
|
}
|
|
39
|
-
|
|
64
|
+
},
|
|
65
|
+
MemberExpression: function (node) {
|
|
66
|
+
if (node.property.name === 'exec' && childProcessIdentifiers.has(node.object)) {
|
|
67
|
+
if (node.parent && node.parent.arguments && node.parent.arguments.length && node.parent.arguments[0].type !== 'Literal') {
|
|
68
|
+
return context.report({ node: node, message: 'Found child_process.exec() with non Literal first argument' });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
40
72
|
};
|
|
41
|
-
|
|
73
|
+
},
|
|
42
74
|
};
|
|
@@ -1,18 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
module.exports = {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'error',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Detects "object.escapeMarkup = false", which can be used with some template engines to disable escaping of HTML entities.',
|
|
8
|
+
category: 'Possible Security Vulnerability',
|
|
9
|
+
recommended: true,
|
|
10
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-disable-mustache-escape.md',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create: function (context) {
|
|
4
14
|
return {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
}
|
|
15
|
+
AssignmentExpression: function (node) {
|
|
16
|
+
if (node.operator === '=') {
|
|
17
|
+
if (node.left.property) {
|
|
18
|
+
if (node.left.property.name === 'escapeMarkup') {
|
|
19
|
+
if (node.right.value === false) {
|
|
20
|
+
context.report({ node: node, message: 'Markup escaping disabled.' });
|
|
21
|
+
}
|
|
14
22
|
}
|
|
23
|
+
}
|
|
15
24
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Identifies eval with expression
|
|
3
3
|
* @author Adam Baldwin
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
6
8
|
//------------------------------------------------------------------------------
|
|
7
9
|
// Rule Definition
|
|
8
10
|
//------------------------------------------------------------------------------
|
|
9
11
|
|
|
10
|
-
module.exports =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
module.exports = {
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'error',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Detects "eval(variable)" which can allow an attacker to run arbitrary code inside your process.',
|
|
17
|
+
category: 'Possible Security Vulnerability',
|
|
18
|
+
recommended: true,
|
|
19
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-eval-with-expression.md',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
create: function (context) {
|
|
14
23
|
return {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
24
|
+
CallExpression: function (node) {
|
|
25
|
+
if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
|
|
26
|
+
context.report({ node: node, message: `eval with argument of type ${node.arguments[0].type}` });
|
|
19
27
|
}
|
|
28
|
+
},
|
|
20
29
|
};
|
|
30
|
+
},
|
|
21
31
|
};
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
// Detects instances of new Buffer(argument)
|
|
3
|
-
// where argument is any non literal value.
|
|
4
|
-
return {
|
|
5
|
-
"NewExpression": function (node) {
|
|
6
|
-
if (node.callee.name === 'Buffer' &&
|
|
7
|
-
node.arguments[0] &&
|
|
8
|
-
node.arguments[0].type != 'Literal') {
|
|
1
|
+
'use strict';
|
|
9
2
|
|
|
10
|
-
|
|
3
|
+
module.exports = {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'error',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Detects instances of new Buffer(argument) where argument is any non-literal value.',
|
|
8
|
+
category: 'Possible Security Vulnerability',
|
|
9
|
+
recommended: true,
|
|
10
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-new-buffer.md',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create: function (context) {
|
|
14
|
+
return {
|
|
15
|
+
NewExpression: function (node) {
|
|
16
|
+
if (node.callee.name === 'Buffer' && node.arguments[0] && node.arguments[0].type !== 'Literal') {
|
|
17
|
+
return context.report({ node: node, message: 'Found new Buffer' });
|
|
11
18
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
19
|
+
},
|
|
16
20
|
};
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -3,37 +3,44 @@
|
|
|
3
3
|
* @author Adam Baldwin
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
6
8
|
//------------------------------------------------------------------------------
|
|
7
9
|
// Rule Definition
|
|
8
10
|
//------------------------------------------------------------------------------
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
module.exports = {
|
|
13
|
+
meta: {
|
|
14
|
+
type: 'error',
|
|
15
|
+
docs: {
|
|
16
|
+
description: 'Detects Express "csrf" middleware setup before "method-override" middleware.',
|
|
17
|
+
category: 'Possible Security Vulnerability',
|
|
18
|
+
recommended: true,
|
|
19
|
+
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-no-csrf-before-method-override.md',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
create: function (context) {
|
|
23
|
+
let csrf = false;
|
|
15
24
|
|
|
16
25
|
return {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
}
|
|
26
|
+
CallExpression: function (node) {
|
|
27
|
+
const token = context.getSourceCode().getTokens(node)[0];
|
|
28
|
+
const nodeValue = token.value;
|
|
29
|
+
|
|
30
|
+
if (nodeValue === 'express') {
|
|
31
|
+
if (!node.callee || !node.callee.property) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (node.callee.property.name === 'methodOverride' && csrf) {
|
|
36
|
+
context.report({ node: node, message: 'express.csrf() middleware found before express.methodOverride()' });
|
|
37
|
+
}
|
|
38
|
+
if (node.callee.property.name === 'csrf') {
|
|
39
|
+
// Keep track of found CSRF
|
|
40
|
+
csrf = true;
|
|
41
|
+
}
|
|
35
42
|
}
|
|
43
|
+
},
|
|
36
44
|
};
|
|
37
|
-
|
|
45
|
+
},
|
|
38
46
|
};
|
|
39
|
-
|