Skip to content

Commit fb1d9ef

Browse files
MarkKragerupnzakas
andauthored
feat: Add meta object documentation for all rules (#79)
* Update .gitignore * Closes #61 * Closes #48 * Update README.md Co-authored-by: Nicholas C. Zakas <[email protected]> * Update README.md Co-authored-by: Nicholas C. Zakas <[email protected]> * Update README.md Co-authored-by: Nicholas C. Zakas <[email protected]> * docs: changed meta urls to rule docs and shortened descriptions to one, markdownfree sentence. * docs: corrected snyk description * docs: updated to link on main Co-authored-by: Nicholas C. Zakas <[email protected]>
1 parent b9a9b7f commit fb1d9ef

16 files changed

+383
-273
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules
2+
.idea

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,27 @@ More information: [Regular Expression DoS and Node.js](docs/regular-expression-d
4444

4545
#### `detect-buffer-noassert`
4646

47-
Detects calls to [`buffer`](https://nodejs.org/api/buffer.html) with `noAssert` flag set
47+
Detect calls to [`buffer`](https://nodejs.org/api/buffer.html) with `noAssert` flag set.
4848

4949
From the Node.js API docs: "Setting `noAssert` to true skips validation of the `offset`. This allows the `offset` to be beyond the end of the `Buffer`."
5050

5151
#### `detect-child-process`
5252

53-
Detects instances of [`child_process`](https://nodejs.org/api/child_process.html) & non-literal [`exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)
53+
Detect instances of [`child_process`](https://nodejs.org/api/child_process.html) & non-literal [`exec()`](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)
5454

5555
More information: [Avoiding Command Injection in Node.js](docs/avoid-command-injection-node.md)
5656

5757
#### `detect-disable-mustache-escape`
5858

5959
Detects `object.escapeMarkup = false`, which can be used with some template engines to disable escaping of HTML entities. This can lead to Cross-Site Scripting (XSS) vulnerabilities.
6060

61-
More information: https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
61+
More information: [OWASP XSS](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS))
6262

6363
#### `detect-eval-with-expression`
6464

6565
Detects `eval(variable)` which can allow an attacker to run arbitrary code inside your process.
6666

67-
More information: http://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript
67+
More information: [What are the security issues with eval in JavaScript?](http://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript)
6868

6969
#### `detect-no-csrf-before-method-override`
7070

@@ -76,7 +76,7 @@ More information: [Bypass Connect CSRF protection by abusing methodOverride Midd
7676

7777
Detects variable in filename argument of `fs` calls, which might allow an attacker to access anything on your system.
7878

79-
More information: https://www.owasp.org/index.php/Path_Traversal
79+
More information: [OWASP Path Traversal](https://www.owasp.org/index.php/Path_Traversal)
8080

8181
#### `detect-non-literal-regexp`
8282

@@ -88,7 +88,7 @@ More information: [Regular Expression DoS and Node.js](docs/regular-expression-d
8888

8989
Detects `require(variable)`, which might allow an attacker to load and run arbitrary code, or access arbitrary files on disk.
9090

91-
More information: http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm
91+
More information: [Where does Node.js and require look for modules?](http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm)
9292

9393
#### `detect-object-injection`
9494

@@ -100,10 +100,14 @@ More information: [The Dangers of Square Bracket Notation](docs/the-dangers-of-s
100100

101101
Detects insecure comparisons (`==`, `!=`, `!==` and `===`), which check input sequentially.
102102

103-
More information: https://codahale.com/a-lesson-in-timing-attacks/
103+
More information: [A lesson in timing attacks](https://codahale.com/a-lesson-in-timing-attacks/)
104104

105105
#### `detect-pseudoRandomBytes`
106106

107107
Detects if `pseudoRandomBytes()` is in use, which might not give you the randomness you need and expect.
108108

109-
More information: http://stackoverflow.com/questions/18130254/randombytes-vs-pseudorandombytes
109+
More information: [Randombytes vs pseudorandombytes](http://stackoverflow.com/questions/18130254/randombytes-vs-pseudorandombytes)
110+
111+
#### `detect-new-buffer`
112+
113+
Detect instances of new Buffer(argument) where argument is any non-literal value.

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rules/detect-buffer-noassert.js

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,59 +11,67 @@
1111

1212
const names = [];
1313

14-
module.exports = function(context) {
15-
16-
const read = [
17-
'readUInt8',
18-
'readUInt16LE',
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-
];
14+
module.exports = {
15+
meta: {
16+
type: 'error',
17+
docs: {
18+
description: 'Detect calls to "buffer" with "noAssert" flag set.',
19+
category: 'Possible Security Vulnerability',
20+
recommended: true,
21+
url: 'https://github.com/nodesecurity/eslint-plugin-security#detect-buffer-noassert'
22+
}
23+
},
24+
create: function(context) {
25+
const read = [
26+
'readUInt8',
27+
'readUInt16LE',
28+
'readUInt16BE',
29+
'readUInt32LE',
30+
'readUInt32BE',
31+
'readInt8',
32+
'readInt16LE',
33+
'readInt16BE',
34+
'readInt32LE',
35+
'readInt32BE',
36+
'readFloatLE',
37+
'readFloatBE',
38+
'readDoubleL',
39+
'readDoubleBE'
40+
];
3241

33-
const 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-
];
42+
const write = [
43+
'writeUInt8',
44+
'writeUInt16LE',
45+
'writeUInt16BE',
46+
'writeUInt32LE',
47+
'writeUInt32BE',
48+
'writeInt8',
49+
'writeInt16LE',
50+
'writeInt16BE',
51+
'writeInt32LE',
52+
'writeInt32BE',
53+
'writeFloatLE',
54+
'writeFloatBE',
55+
'writeDoubleLE',
56+
'writeDoubleBE'
57+
];
4958

50-
return {
51-
'MemberExpression': function (node) {
52-
let index;
53-
if (read.indexOf(node.property.name) !== -1) {
54-
index = 1;
55-
}
56-
else if (write.indexOf(node.property.name) !== -1) {
57-
index = 2;
58-
}
59+
return {
60+
'MemberExpression': function(node) {
61+
let index;
62+
if (read.indexOf(node.property.name) !== -1) {
63+
index = 1;
64+
}
65+
else if (write.indexOf(node.property.name) !== -1) {
66+
index = 2;
67+
}
5968

60-
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
61-
const token = context.getTokens(node)[0];
62-
return context.report(node, `Found Buffer.${ node.property.name } with noAssert flag set true`);
69+
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
70+
const token = context.getTokens(node)[0];
71+
return context.report(node, `Found Buffer.${node.property.name} with noAssert flag set true`);
6372

73+
}
6474
}
65-
}
66-
67-
};
68-
75+
};
76+
}
6977
};

rules/detect-child-process.js

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,42 @@
1111

1212
const names = [];
1313

14-
module.exports = function(context) {
15-
16-
return {
17-
'CallExpression': function (node) {
18-
const token = context.getTokens(node)[0];
19-
if (node.callee.name === 'require') {
20-
const args = node.arguments[0];
21-
if (args && args.type === 'Literal' && args.value === 'child_process') {
22-
if (node.parent.type === 'VariableDeclarator') {
23-
names.push(node.parent.id.name);
24-
}
25-
else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
26-
names.push(node.parent.left.name);
14+
module.exports = {
15+
meta: {
16+
type: 'error',
17+
docs: {
18+
description: 'Detect instances of "child_process" & non-literal "exec()" calls.',
19+
category: 'Possible Security Vulnerability',
20+
recommended: true,
21+
url: 'https://github.com/nodesecurity/eslint-plugin-security/blob/main/docs/avoid-command-injection-node.md'
22+
}
23+
},
24+
create: function(context) {
25+
return {
26+
'CallExpression': function(node) {
27+
const token = context.getTokens(node)[0];
28+
if (node.callee.name === 'require') {
29+
const args = node.arguments[0];
30+
if (args && args.type === 'Literal' && args.value === 'child_process') {
31+
if (node.parent.type === 'VariableDeclarator') {
32+
names.push(node.parent.id.name);
33+
}
34+
else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
35+
names.push(node.parent.left.name);
36+
}
37+
return context.report(node, 'Found require("child_process")');
2738
}
28-
return context.report(node, 'Found require("child_process")');
2939
}
30-
}
31-
},
32-
'MemberExpression': function (node) {
33-
const token = context.getTokens(node)[0];
34-
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
35-
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
36-
return context.report(node, 'Found child_process.exec() with non Literal first argument');
40+
},
41+
'MemberExpression': function(node) {
42+
const token = context.getTokens(node)[0];
43+
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
44+
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
45+
return context.report(node, 'Found child_process.exec() with non Literal first argument');
46+
}
3747
}
3848
}
39-
}
40-
41-
};
4249

50+
};
51+
}
4352
};
Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
1-
21
'use strict';
32

4-
module.exports = function(context) {
5-
6-
return {
7-
'AssignmentExpression': function(node) {
8-
if (node.operator === '=') {
9-
if (node.left.property) {
10-
if (node.left.property.name === 'escapeMarkup') {
11-
if (node.right.value === false) {
12-
context.report(node, 'Markup escaping disabled.');
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/nodesecurity/eslint-plugin-security#detect-disable-mustache-escape'
11+
}
12+
},
13+
create: function(context) {
14+
return {
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, 'Markup escaping disabled.');
21+
}
1322
}
1423
}
1524
}
1625
}
17-
}
18-
};
19-
26+
};
27+
}
2028
};

rules/detect-eval-with-expression.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,23 @@
99
// Rule Definition
1010
//------------------------------------------------------------------------------
1111

12-
module.exports = function(context) {
13-
14-
return {
15-
'CallExpression': function(node) {
16-
if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
17-
context.report(node, `eval with argument of type ${ node.arguments[0].type}`);
18-
}
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/nodesecurity/eslint-plugin-security#detect-eval-with-expression'
1920
}
20-
};
21+
},
22+
create: function(context) {
23+
return {
24+
'CallExpression': function(node) {
25+
if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
26+
context.report(node, `eval with argument of type ${node.arguments[0].type}`);
27+
}
28+
}
29+
};
30+
}
2131
};

rules/detect-new-buffer.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
'use strict';
22

33

4-
module.exports = function (context) {
5-
// Detects instances of new Buffer(argument)
6-
// where argument is any non literal value.
7-
return {
8-
'NewExpression': function (node) {
9-
if (node.callee.name === 'Buffer' &&
4+
module.exports = {
5+
meta: {
6+
type: 'error',
7+
docs: {
8+
description: 'Detect instances of new Buffer(argument) where argument is any non-literal value.',
9+
category: 'Possible Security Vulnerability',
10+
recommended: true,
11+
url: 'https://github.com/nodesecurity/eslint-plugin-security/blob/main/README.md'
12+
}
13+
},
14+
create: function(context) {
15+
return {
16+
'NewExpression': function(node) {
17+
if (node.callee.name === 'Buffer' &&
1018
node.arguments[0] &&
1119
node.arguments[0].type !== 'Literal') {
1220

13-
return context.report(node, 'Found new Buffer');
21+
return context.report(node, 'Found new Buffer');
22+
}
1423
}
15-
16-
17-
18-
}
19-
};
20-
24+
};
25+
}
2126
};

0 commit comments

Comments
 (0)