eslint-plugin-security 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +4 -1
- package/index.js +22 -0
- package/package.json +3 -1
- package/rules/detect-buffer-noassert.js +1 -6
- package/rules/detect-child-process.js +2 -6
- package/rules/detect-new-buffer.js +1 -8
- package/rules/detect-non-literal-fs-filename.js +2 -6
- package/rules/detect-non-literal-regexp.js +1 -4
- package/rules/detect-non-literal-require.js +1 -5
- package/rules/detect-object-injection.js +3 -3
- package/rules/detect-possible-timing-attacks.js +2 -6
- package/rules/detect-pseudoRandomBytes.js +1 -5
- package/test/detect-buffer-noassert.js +2 -2
- package/test/detect-child-process.js +3 -3
- package/test/detect-new-buffer.js +1 -1
- package/test/detect-non-literal-fs-filename.js +1 -1
- package/test/detect-non-literal-regexp.js +1 -1
- package/test/detect-non-literal-require.js +1 -1
- package/test/detect-object-injection.js +2 -2
- package/test/detect-possible-timing-attacks.js +2 -2
- package/test/detect-pseudoRandomBytes.js +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
1.4.0 / 2017-06-12
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
* Add recommended ruleset to the usage example
|
|
5
|
+
* Removes filenames from error output
|
|
6
|
+
|
|
7
|
+
1.3.0 / 2017-02-09
|
|
8
|
+
==================
|
|
9
|
+
|
|
10
|
+
* README.md - document detect-disable-mustache-escape rule
|
|
11
|
+
* README.md - documentation detect-new-buffer rule
|
|
12
|
+
* Fixed crash with `detect-no-csrf-before-method-override` rule.
|
|
13
|
+
* Style guide applied to all the code involving the tests
|
|
14
|
+
* Removing a repeated test and style changes
|
|
15
|
+
* ESLint added to the workflow
|
|
16
|
+
* Removed not needed variables
|
|
17
|
+
* Fix to a problem with a rule detected implementing the tests
|
|
18
|
+
* Test engine with tests for all the rules
|
|
19
|
+
* Add additional information to README for each rule
|
|
20
|
+
|
|
21
|
+
1.2.0 / 2016-01-21
|
|
22
|
+
==================
|
|
23
|
+
|
|
24
|
+
* updated to check for new RegExp too
|
|
25
|
+
|
|
26
|
+
1.1.0 / 2016-01-06
|
|
27
|
+
==================
|
|
28
|
+
|
|
29
|
+
* adding eslint rule to detect new buffer hotspot
|
|
30
|
+
|
|
31
|
+
1.0.0 / 2015-11-15
|
|
32
|
+
==================
|
|
33
|
+
|
|
34
|
+
* rules disabled by default
|
package/README.md
CHANGED
|
@@ -15,6 +15,9 @@ Add the following to your `.eslintrc` file:
|
|
|
15
15
|
```js
|
|
16
16
|
"plugins": [
|
|
17
17
|
"security"
|
|
18
|
+
],
|
|
19
|
+
"extends": [
|
|
20
|
+
"plugin:security/recommended"
|
|
18
21
|
]
|
|
19
22
|
```
|
|
20
23
|
|
|
@@ -94,7 +97,7 @@ More information: http://www.bennadel.com/blog/2169-where-does-node-js-and-requi
|
|
|
94
97
|
|
|
95
98
|
Detects `variable[key]` as a left- or right-hand assignment operand.
|
|
96
99
|
|
|
97
|
-
More information: https://blog.liftsecurity.io/2015/01/
|
|
100
|
+
More information: https://blog.liftsecurity.io/2015/01/14/the-dangers-of-square-bracket-notation/
|
|
98
101
|
|
|
99
102
|
#### `detect-possible-timing-attacks`
|
|
100
103
|
|
package/index.js
CHANGED
|
@@ -34,5 +34,27 @@ module.exports = {
|
|
|
34
34
|
'detect-disable-mustache-escape': 0,
|
|
35
35
|
'detect-object-injection': 0,
|
|
36
36
|
'detect-new-buffer': 0
|
|
37
|
+
},
|
|
38
|
+
configs: {
|
|
39
|
+
recommended: {
|
|
40
|
+
plugins: [
|
|
41
|
+
'security'
|
|
42
|
+
],
|
|
43
|
+
rules: {
|
|
44
|
+
'security/detect-buffer-noassert': 'warn',
|
|
45
|
+
'security/detect-child-process': 'warn',
|
|
46
|
+
'security/detect-disable-mustache-escape': 'warn',
|
|
47
|
+
'security/detect-eval-with-expression': 'warn',
|
|
48
|
+
'security/detect-new-buffer': 'warn',
|
|
49
|
+
'security/detect-no-csrf-before-method-override': 'warn',
|
|
50
|
+
'security/detect-non-literal-fs-filename': 'warn',
|
|
51
|
+
'security/detect-non-literal-regexp': 'warn',
|
|
52
|
+
'security/detect-non-literal-require': 'warn',
|
|
53
|
+
'security/detect-object-injection': 'warn',
|
|
54
|
+
'security/detect-possible-timing-attacks': 'warn',
|
|
55
|
+
'security/detect-pseudoRandomBytes': 'warn',
|
|
56
|
+
'security/detect-unsafe-regex': 'warn'
|
|
57
|
+
}
|
|
58
|
+
}
|
|
37
59
|
}
|
|
38
60
|
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-security",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Security rules for eslint",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"changelog": "changelog eslint-plugin-security all > CHANGELOG.md",
|
|
7
8
|
"test": "./node_modules/.bin/mocha test/**/*",
|
|
8
9
|
"lint": "./node_modules/.bin/eslint .",
|
|
9
10
|
"cont-int": "npm test && npm run-script lint"
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
"safe-regex": "^1.1.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
31
|
+
"changelog": "1.3.0",
|
|
30
32
|
"eslint": "^2.10.1",
|
|
31
33
|
"eslint-config-nodesecurity": "^1.3.1",
|
|
32
34
|
"mocha": "^2.4.5"
|
|
@@ -47,11 +47,6 @@ module.exports = function(context) {
|
|
|
47
47
|
"writeDoubleBE"
|
|
48
48
|
];
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
var getSource = function (token) {
|
|
52
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
50
|
return {
|
|
56
51
|
"MemberExpression": function (node) {
|
|
57
52
|
var index;
|
|
@@ -63,7 +58,7 @@ module.exports = function(context) {
|
|
|
63
58
|
|
|
64
59
|
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
|
|
65
60
|
var token = context.getTokens(node)[0];
|
|
66
|
-
return context.report(node, 'Found Buffer.' + node.property.name + ' with noAssert flag set true
|
|
61
|
+
return context.report(node, 'Found Buffer.' + node.property.name + ' with noAssert flag set true');
|
|
67
62
|
|
|
68
63
|
}
|
|
69
64
|
}
|
|
@@ -13,10 +13,6 @@ module.exports = function(context) {
|
|
|
13
13
|
|
|
14
14
|
"use strict";
|
|
15
15
|
|
|
16
|
-
var getSource = function (token) {
|
|
17
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
16
|
return {
|
|
21
17
|
"CallExpression": function (node) {
|
|
22
18
|
var token = context.getTokens(node)[0];
|
|
@@ -28,7 +24,7 @@ module.exports = function(context) {
|
|
|
28
24
|
} else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
|
|
29
25
|
names.push(node.parent.left.name);
|
|
30
26
|
}
|
|
31
|
-
return context.report(node, 'Found require("child_process")
|
|
27
|
+
return context.report(node, 'Found require("child_process")');
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
},
|
|
@@ -36,7 +32,7 @@ module.exports = function(context) {
|
|
|
36
32
|
var token = context.getTokens(node)[0];
|
|
37
33
|
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
|
|
38
34
|
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
|
|
39
|
-
return context.report(node, 'Found child_process.exec() with non Literal first argument
|
|
35
|
+
return context.report(node, 'Found child_process.exec() with non Literal first argument');
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
module.exports = function (context) {
|
|
2
|
-
|
|
3
|
-
var getSource = function (node) {
|
|
4
|
-
var token = context.getTokens(node)[0];
|
|
5
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
2
|
// Detects instances of new Buffer(argument)
|
|
10
3
|
// where argument is any non literal value.
|
|
11
4
|
return {
|
|
@@ -14,7 +7,7 @@ module.exports = function (context) {
|
|
|
14
7
|
node.arguments[0] &&
|
|
15
8
|
node.arguments[0].type != 'Literal') {
|
|
16
9
|
|
|
17
|
-
return context.report(node, "Found new Buffer
|
|
10
|
+
return context.report(node, "Found new Buffer");
|
|
18
11
|
}
|
|
19
12
|
|
|
20
13
|
|
|
@@ -15,10 +15,6 @@ module.exports = function(context) {
|
|
|
15
15
|
|
|
16
16
|
"use strict";
|
|
17
17
|
|
|
18
|
-
var getSource = function (token) {
|
|
19
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
18
|
return {
|
|
23
19
|
"MemberExpression": function (node) {
|
|
24
20
|
var result = [];
|
|
@@ -36,13 +32,13 @@ module.exports = function(context) {
|
|
|
36
32
|
|
|
37
33
|
if (result.length > 0) {
|
|
38
34
|
var token = context.getTokens(node)[0];
|
|
39
|
-
return context.report(node, 'Found fs.' + node.property.name + ' with non literal argument at index ' + result.join(',')
|
|
35
|
+
return context.report(node, 'Found fs.' + node.property.name + ' with non literal argument at index ' + result.join(','));
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
|
|
43
39
|
/*
|
|
44
40
|
if (node.parent && node.parent.arguments && node.parent.arguments[index].value) {
|
|
45
|
-
return context.report(node, 'found Buffer.' + node.property.name + ' with noAssert flag set true
|
|
41
|
+
return context.report(node, 'found Buffer.' + node.property.name + ' with noAssert flag set true');
|
|
46
42
|
|
|
47
43
|
}
|
|
48
44
|
*/
|
|
@@ -12,16 +12,13 @@ module.exports = function(context) {
|
|
|
12
12
|
|
|
13
13
|
"use strict";
|
|
14
14
|
|
|
15
|
-
var getSource = function(token) {
|
|
16
|
-
return token.loc.start.line + ': ' + context.getSourceLines().slice(token.loc.start.line - 1, token.loc.end.line).join('\n\t');
|
|
17
|
-
}
|
|
18
15
|
return {
|
|
19
16
|
"NewExpression": function(node) {
|
|
20
17
|
if (node.callee.name === 'RegExp') {
|
|
21
18
|
var args = node.arguments;
|
|
22
19
|
if (args && args.length > 0 && args[0].type !== 'Literal') {
|
|
23
20
|
var token = context.getTokens(node)[0];
|
|
24
|
-
return context.report(node, 'Found non-literal argument to RegExp Constructor
|
|
21
|
+
return context.report(node, 'Found non-literal argument to RegExp Constructor');
|
|
25
22
|
}
|
|
26
23
|
}
|
|
27
24
|
|
|
@@ -11,17 +11,13 @@ module.exports = function(context) {
|
|
|
11
11
|
|
|
12
12
|
"use strict";
|
|
13
13
|
|
|
14
|
-
var getSource = function (token) {
|
|
15
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
return {
|
|
19
15
|
"CallExpression": function (node) {
|
|
20
16
|
if (node.callee.name === 'require') {
|
|
21
17
|
var args = node.arguments;
|
|
22
18
|
if (args && args.length > 0 && args[0].type !== 'Literal') {
|
|
23
19
|
var token = context.getTokens(node)[0];
|
|
24
|
-
return context.report(node, 'Found non-literal argument in require
|
|
20
|
+
return context.report(node, 'Found non-literal argument in require');
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
23
|
|
|
@@ -59,13 +59,13 @@ var isChanged = false;
|
|
|
59
59
|
var token = context.getTokens(node)[0];
|
|
60
60
|
if (node.property.type === 'Identifier') {
|
|
61
61
|
if (node.parent.type === 'VariableDeclarator') {
|
|
62
|
-
context.report(node, 'Variable Assigned to Object Injection Sink
|
|
62
|
+
context.report(node, 'Variable Assigned to Object Injection Sink');
|
|
63
63
|
|
|
64
64
|
} else if (node.parent.type === 'CallExpression') {
|
|
65
65
|
// console.log(node.parent)
|
|
66
|
-
context.report(node, 'Function Call Object Injection Sink
|
|
66
|
+
context.report(node, 'Function Call Object Injection Sink');
|
|
67
67
|
} else {
|
|
68
|
-
context.report(node, 'Generic Object Injection Sink
|
|
68
|
+
context.report(node, 'Generic Object Injection Sink');
|
|
69
69
|
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -32,10 +32,6 @@ module.exports = function(context) {
|
|
|
32
32
|
|
|
33
33
|
"use strict";
|
|
34
34
|
|
|
35
|
-
var getSource = function (token) {
|
|
36
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
35
|
return {
|
|
40
36
|
"IfStatement": function(node) {
|
|
41
37
|
if (node.test && node.test.type === 'BinaryExpression') {
|
|
@@ -46,14 +42,14 @@ module.exports = function(context) {
|
|
|
46
42
|
if (node.test.left) {
|
|
47
43
|
var left = containsKeyword(node.test.left);
|
|
48
44
|
if (left) {
|
|
49
|
-
return context.report(node, "Potential timing attack, left side: " + left
|
|
45
|
+
return context.report(node, "Potential timing attack, left side: " + left);
|
|
50
46
|
}
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
if (node.test.right) {
|
|
54
50
|
var right = containsKeyword(node.test.right);
|
|
55
51
|
if (right) {
|
|
56
|
-
return context.report(node, "Potential timing attack, right side: " + right
|
|
52
|
+
return context.report(node, "Potential timing attack, right side: " + right);
|
|
57
53
|
}
|
|
58
54
|
}
|
|
59
55
|
}
|
|
@@ -11,15 +11,11 @@ module.exports = function(context) {
|
|
|
11
11
|
|
|
12
12
|
"use strict";
|
|
13
13
|
|
|
14
|
-
var getSource = function (token) {
|
|
15
|
-
return token.loc.start.line+ ': ' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
return {
|
|
19
15
|
"MemberExpression": function (node) {
|
|
20
16
|
if (node.property.name === 'pseudoRandomBytes') {
|
|
21
17
|
var token = context.getTokens(node)[0];
|
|
22
|
-
return context.report(node, 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers
|
|
18
|
+
return context.report(node, 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers');
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
|
|
@@ -14,7 +14,7 @@ tester.run(ruleName, Rule, {
|
|
|
14
14
|
invalid: [
|
|
15
15
|
{
|
|
16
16
|
code: invalid,
|
|
17
|
-
errors: [{ message:
|
|
17
|
+
errors: [{ message: 'Found Buffer.readUInt8 with noAssert flag set true' }]
|
|
18
18
|
}
|
|
19
19
|
]
|
|
20
20
|
});
|
|
@@ -24,7 +24,7 @@ tester.run(`${ruleName} (false)`, Rule, {
|
|
|
24
24
|
invalid: [
|
|
25
25
|
{
|
|
26
26
|
code: invalid,
|
|
27
|
-
errors: [{ message:
|
|
27
|
+
errors: [{ message: 'Found Buffer.readUInt8 with noAssert flag set true' }]
|
|
28
28
|
}
|
|
29
29
|
]
|
|
30
30
|
});
|
|
@@ -16,7 +16,7 @@ tester.run(`${ruleName} (require("child_process"))`, Rule, {
|
|
|
16
16
|
invalid: [
|
|
17
17
|
{
|
|
18
18
|
code: invalidRequire,
|
|
19
|
-
errors: [{ message:
|
|
19
|
+
errors: [{ message: 'Found require("child_process")' }]
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
});
|
|
@@ -28,8 +28,8 @@ tester.run(`${ruleName} (child_process.exec() wih non literal 1st arg.)`, Rule,
|
|
|
28
28
|
{
|
|
29
29
|
code: invalidExec,
|
|
30
30
|
errors: [
|
|
31
|
-
{ message:
|
|
32
|
-
{ message:
|
|
31
|
+
{ message: 'Found require("child_process")' },
|
|
32
|
+
{ message: 'Found child_process.exec() with non Literal first argument' }]
|
|
33
33
|
}
|
|
34
34
|
]
|
|
35
35
|
});
|
|
@@ -13,7 +13,7 @@ tester.run(ruleName, require(`../rules/${ruleName}`), {
|
|
|
13
13
|
invalid: [
|
|
14
14
|
{
|
|
15
15
|
code: invalid,
|
|
16
|
-
errors: [{ message:
|
|
16
|
+
errors: [{ message: 'Found fs.open with non literal argument at index 0' }]
|
|
17
17
|
}
|
|
18
18
|
]
|
|
19
19
|
});
|
|
@@ -12,7 +12,7 @@ tester.run(ruleName, require(`../rules/${ruleName}`), {
|
|
|
12
12
|
invalid: [
|
|
13
13
|
{
|
|
14
14
|
code: invalid,
|
|
15
|
-
errors: [{ message:
|
|
15
|
+
errors: [{ message: 'Found non-literal argument to RegExp Constructor' }]
|
|
16
16
|
}
|
|
17
17
|
]
|
|
18
18
|
});
|
|
@@ -19,7 +19,7 @@ const invalidGeneric = 'var a = {}; a[b] = 4';
|
|
|
19
19
|
// invalid: [
|
|
20
20
|
// {
|
|
21
21
|
// code: invalidVariable,
|
|
22
|
-
// errors: [{ message:
|
|
22
|
+
// errors: [{ message: 'Variable Assigned to Object Injection Sink' }]
|
|
23
23
|
// }
|
|
24
24
|
// ]
|
|
25
25
|
// });
|
|
@@ -41,7 +41,7 @@ tester.run(`${ruleName} (Generic)`, Rule, {
|
|
|
41
41
|
invalid: [
|
|
42
42
|
{
|
|
43
43
|
code: invalidGeneric,
|
|
44
|
-
errors: [{ message:
|
|
44
|
+
errors: [{ message: 'Generic Object Injection Sink' }]
|
|
45
45
|
}
|
|
46
46
|
]
|
|
47
47
|
});
|
|
@@ -19,7 +19,7 @@ tester.run(`${ruleName} (left side)`, Rule, {
|
|
|
19
19
|
invalid: [
|
|
20
20
|
{
|
|
21
21
|
code: invalidLeft,
|
|
22
|
-
errors: [{ message:
|
|
22
|
+
errors: [{ message: 'Potential timing attack, left side: true' }]
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
});
|
|
@@ -30,7 +30,7 @@ tester.run(`${ruleName} (right side)`, Rule, {
|
|
|
30
30
|
invalid: [
|
|
31
31
|
{
|
|
32
32
|
code: invalidRigth,
|
|
33
|
-
errors: [{ message:
|
|
33
|
+
errors: [{ message: 'Potential timing attack, right side: true' }]
|
|
34
34
|
}
|
|
35
35
|
]
|
|
36
36
|
});
|
|
@@ -12,7 +12,7 @@ tester.run(ruleName, require(`../rules/${ruleName}`), {
|
|
|
12
12
|
invalid: [
|
|
13
13
|
{
|
|
14
14
|
code: invalid,
|
|
15
|
-
errors: [{ message:
|
|
15
|
+
errors: [{ message: 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers' }]
|
|
16
16
|
}
|
|
17
17
|
]
|
|
18
18
|
});
|