eslint-plugin-security 1.0.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/.eslintrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "nodesecurity"
3
+ }
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
@@ -1,7 +1,8 @@
1
1
  # eslint-plugin-security
2
+
2
3
  ESLint rules for Node Security
3
4
 
4
- Probably not something you want to just toss and leave in a project. It will help identify potential security hotspots, but finds a lot of false positives that needs triaged by a human.
5
+ This project will help identify potential security hotspots, but finds a lot of false positives which need triage by a human.
5
6
 
6
7
  ### Installation
7
8
 
@@ -14,20 +15,98 @@ Add the following to your `.eslintrc` file:
14
15
  ```js
15
16
  "plugins": [
16
17
  "security"
18
+ ],
19
+ "extends": [
20
+ "plugin:security/recommended"
17
21
  ]
18
22
  ```
23
+
24
+
25
+ ## Developer guide
26
+
27
+ - Use [GitHub pull requests](https://help.github.com/articles/using-pull-requests).
28
+ - Conventions:
29
+ - We use our [custom ESLint setup](https://github.com/nodesecurity/eslint-config-nodesecurity).
30
+ - Please implement a test for each new rule and use this command to be sure the new code respects the style guide and the tests keep passing:
31
+ ```sh
32
+ npm run-script cont-int
33
+ ```
34
+
35
+ ### Tests
36
+ ```sh
37
+ npm test
38
+ ```
39
+
19
40
  ### Rules
20
41
 
21
- - `detect-unsafe-regex` - Locates potentially unsafe regular expressions
22
- - `detect-buffer-noassert` - Detects calls to buffer with noassert flag set
23
- - `detect-child-process` - Detects instances of child_process & non-literal cp.exec()
24
- - `detect-disable-mustache-escape` -
25
- - `detect-eval-with-expression` - Detects eval(var)
26
- - `detect-no-csrf-before-method-override` - Detects Express.csrf before method-override
27
- - `detect-non-literal-fs-filename` - Detects var in filename argument of fs calls
28
- - `detect-non-literal-regexp` - Detects RegExp(var)
29
- - `detect-non-literal-require` - Detects require(var)
30
- - `detect-object-injection` - Detects var[var]
31
- - `detect-possible-timing-attacks` - Detects insecure comparisons (== != !== ===)
32
- - `detect-pseudoRandomBytes` - Detects if pseudoRandomBytes() is in use
42
+ #### `detect-unsafe-regex`
43
+
44
+ Locates potentially unsafe regular expressions, which may take a very long time to run, blocking the event loop.
45
+
46
+ More information: https://blog.liftsecurity.io/2014/11/03/regular-expression-dos-and-node.js
47
+
48
+ #### `detect-buffer-noassert`
49
+
50
+ Detects calls to [`buffer`](https://nodejs.org/api/buffer.html) with `noAssert` flag set
51
+
52
+ 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`."
53
+
54
+ #### `detect-child-process`
55
+
56
+ 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)
57
+
58
+ More information: https://blog.liftsecurity.io/2014/08/19/Avoid-Command-Injection-Node.js
59
+
60
+ #### `detect-disable-mustache-escape`
61
+
62
+ 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.
63
+
64
+ More information: https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
65
+
66
+ #### `detect-eval-with-expression`
67
+
68
+ Detects `eval(variable)` which can allow an attacker to run arbitary code inside your process.
69
+
70
+ More information: http://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript
71
+
72
+ #### `detect-no-csrf-before-method-override`
73
+
74
+ Detects Express `csrf` middleware setup before `method-override` middleware. This can allow `GET` requests (which are not checked by `csrf`) to turn into `POST` requests later.
75
+
76
+ More information: https://blog.liftsecurity.io/2013/09/07/bypass-connect-csrf-protection-by-abusing
77
+
78
+ #### `detect-non-literal-fs-filename`
79
+
80
+ Detects variable in filename argument of `fs` calls, which might allow an attacker to access anything on your system.
81
+
82
+ More information: https://www.owasp.org/index.php/Path_Traversal
83
+
84
+ #### `detect-non-literal-regexp`
85
+
86
+ Detects `RegExp(variable)`, which might allow an attacker to DOS your server with a long-running regular expression.
87
+
88
+ More information: https://blog.liftsecurity.io/2014/11/03/regular-expression-dos-and-node.js
89
+
90
+ #### `detect-non-literal-require`
91
+
92
+ Detects `require(variable)`, which might allow an attacker to load and run arbitrary code, or access arbitrary files on disk.
93
+
94
+ More information: http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm
95
+
96
+ #### `detect-object-injection`
97
+
98
+ Detects `variable[key]` as a left- or right-hand assignment operand.
99
+
100
+ More information: https://blog.liftsecurity.io/2015/01/14/the-dangers-of-square-bracket-notation/
101
+
102
+ #### `detect-possible-timing-attacks`
103
+
104
+ Detects insecure comparisons (`==`, `!=`, `!==` and `===`), which check input sequentially.
105
+
106
+ More information: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/
107
+
108
+ #### `detect-pseudoRandomBytes`
109
+
110
+ Detects if `pseudoRandomBytes()` is in use, which might not give you the randomness you need and expect.
33
111
 
112
+ More information: http://stackoverflow.com/questions/18130254/randombytes-vs-pseudorandombytes
package/index.js CHANGED
@@ -17,7 +17,8 @@ module.exports = {
17
17
  'detect-buffer-noassert': require('./rules/detect-buffer-noassert'),
18
18
  'detect-child-process': require('./rules/detect-child-process'),
19
19
  'detect-disable-mustache-escape': require('./rules/detect-disable-mustache-escape'),
20
- 'detect-object-injection': require('./rules/detect-object-injection')
20
+ 'detect-object-injection': require('./rules/detect-object-injection'),
21
+ 'detect-new-buffer': require('./rules/detect-new-buffer')
21
22
  },
22
23
  rulesConfig: {
23
24
  'detect-unsafe-regex': 0,
@@ -31,6 +32,29 @@ module.exports = {
31
32
  'detect-buffer-noassert': 0,
32
33
  'detect-child-process': 0,
33
34
  'detect-disable-mustache-escape': 0,
34
- 'detect-object-injection': 0
35
+ 'detect-object-injection': 0,
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
+ }
35
59
  }
36
60
  };
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "eslint-plugin-security",
3
- "version": "1.0.0",
3
+ "version": "1.4.0",
4
4
  "description": "Security rules for eslint",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "changelog": "changelog eslint-plugin-security all > CHANGELOG.md",
8
+ "test": "./node_modules/.bin/mocha test/**/*",
9
+ "lint": "./node_modules/.bin/eslint .",
10
+ "cont-int": "npm test && npm run-script lint"
8
11
  },
9
12
  "repository": {
10
13
  "type": "git",
@@ -25,6 +28,9 @@
25
28
  "safe-regex": "^1.1.0"
26
29
  },
27
30
  "devDependencies": {
28
- "eslint": "^1.8.0"
31
+ "changelog": "1.3.0",
32
+ "eslint": "^2.10.1",
33
+ "eslint-config-nodesecurity": "^1.3.1",
34
+ "mocha": "^2.4.5"
29
35
  }
30
36
  }
@@ -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:\n\t' + getSource(token));
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")\n\t' + getSource(token));
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\n\t' + getSource(token));
35
+ return context.report(node, 'Found child_process.exec() with non Literal first argument');
40
36
  }
41
37
  }
42
38
  }
@@ -0,0 +1,19 @@
1
+ module.exports = function (context) {
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') {
9
+
10
+ return context.report(node, "Found new Buffer");
11
+ }
12
+
13
+
14
+
15
+ }
16
+ };
17
+
18
+ }
19
+
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Check and see if CSRF middleware is before methodOverride
3
- * @author Adam Baldwin
2
+ * Check and see if CSRF middleware is before methodOverride
3
+ * @author Adam Baldwin
4
4
  */
5
5
 
6
6
  //------------------------------------------------------------------------------
@@ -20,6 +20,10 @@ module.exports = function(context) {
20
20
  nodeValue = token.value;
21
21
 
22
22
  if (nodeValue === "express") {
23
+ if (!node.callee || !node.callee.property) {
24
+ return;
25
+ }
26
+
23
27
  if (node.callee.property.name === "methodOverride" && csrf) {
24
28
  context.report(node, "express.csrf() middleware found before express.methodOverride()");
25
29
  }
@@ -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(',') + '\n\t' + getSource(token));
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:\n\t' + getSource(token));
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
- "CallExpression": function(node) {
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\n\t' + getSource(token));
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\n\t' + getSource(token));
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: ' + context.getFilename() + ': ' + token.loc.start.line+ '\n\t' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t') + '\n\n');
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: ' + context.getFilename() + ': ' + token.loc.start.line+ '\n\t' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t') + '\n\n');
66
+ context.report(node, 'Function Call Object Injection Sink');
67
67
  } else {
68
- context.report(node, 'Generic Object Injection Sink: ' + context.getFilename() + ': ' + token.loc.start.line+ '\n\t' + context.getSourceLines().slice(token.loc.start.line-1, token.loc.end.line).join('\n\t') + '\n\n');
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 + '\n\t' + getSource(token));
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 + '\n\t' + getSource(token));
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:\n\t' + getSource(token));
18
+ return context.report(node, 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers');
23
19
  }
24
20
  }
25
21
 
@@ -1,7 +1,7 @@
1
1
  var safe = require('safe-regex');
2
2
  /**
3
3
  * Check if the regex is evil or not using the safe-regex module
4
- * @author Adam Baldwin
4
+ * @author Adam Baldwin
5
5
  */
6
6
 
7
7
  //------------------------------------------------------------------------------
@@ -11,9 +11,6 @@ var safe = require('safe-regex');
11
11
  module.exports = function(context) {
12
12
 
13
13
  "use strict";
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
14
 
18
15
  return {
19
16
  "Literal": function(node) {
@@ -23,7 +20,14 @@ module.exports = function(context) {
23
20
 
24
21
  if (nodeType === "RegularExpression") {
25
22
  if (!safe(nodeValue)) {
26
- context.report(node, "Unsafe Regular Expression\n" + getSource(token));
23
+ context.report(node, "Unsafe Regular Expression");
24
+ }
25
+ }
26
+ },
27
+ "NewExpression": function(node) {
28
+ if (node.callee.name == "RegExp" && node.arguments && node.arguments.length > 0 && node.arguments[0].type == "Literal") {
29
+ if (!safe(node.arguments[0].value)) {
30
+ context.report(node, "Unsafe Regular Expression (new RegExp)");
27
31
  }
28
32
  }
29
33
  }
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-buffer-noassert';
7
+ const Rule = require(`../rules/${ruleName}`);
8
+
9
+ const invalid = 'a.readUInt8(0, true);';
10
+
11
+
12
+ tester.run(ruleName, Rule, {
13
+ valid: [{ code: 'a.readUInt8(0);' }],
14
+ invalid: [
15
+ {
16
+ code: invalid,
17
+ errors: [{ message: 'Found Buffer.readUInt8 with noAssert flag set true' }]
18
+ }
19
+ ]
20
+ });
21
+
22
+ tester.run(`${ruleName} (false)`, Rule, {
23
+ valid: [{ code: 'a.readUInt8(0, false);' }],
24
+ invalid: [
25
+ {
26
+ code: invalid,
27
+ errors: [{ message: 'Found Buffer.readUInt8 with noAssert flag set true' }]
28
+ }
29
+ ]
30
+ });
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-child-process';
7
+ const Rule = require(`../rules/${ruleName}`);
8
+
9
+ const valid = 'child_process.exec(\'ls\')';
10
+ const invalidRequire = 'require(\'child_process\')';
11
+ const invalidExec = 'var child = require(\'child_process\'); child.exec(com)';
12
+
13
+
14
+ tester.run(`${ruleName} (require("child_process"))`, Rule, {
15
+ valid: [{ code: valid }],
16
+ invalid: [
17
+ {
18
+ code: invalidRequire,
19
+ errors: [{ message: 'Found require("child_process")' }]
20
+ }
21
+ ]
22
+ });
23
+
24
+
25
+ tester.run(`${ruleName} (child_process.exec() wih non literal 1st arg.)`, Rule, {
26
+ valid: [{ code: valid }],
27
+ invalid: [
28
+ {
29
+ code: invalidExec,
30
+ errors: [
31
+ { message: 'Found require("child_process")' },
32
+ { message: 'Found child_process.exec() with non Literal first argument' }]
33
+ }
34
+ ]
35
+ });
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-disable-mustache-escape';
7
+
8
+
9
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
10
+ valid: [{ code: 'escapeMarkup = false' }],
11
+ invalid: [
12
+ {
13
+ code: 'a.escapeMarkup = false',
14
+ errors: [{ message: 'Markup escaping disabled.' }]
15
+ }
16
+ ]
17
+ });
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-eval-with-expression';
7
+
8
+
9
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
10
+ valid: [{ code: 'eval(\'alert()\')' }],
11
+ invalid: [
12
+ {
13
+ code: 'eval(a);',
14
+ errors: [{ message: 'eval with argument of type Identifier' }]
15
+ }
16
+ ]
17
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-new-buffer';
7
+ const invalid = 'var a = new Buffer(c)';
8
+
9
+
10
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
11
+ valid: [{ code: 'var a = new Buffer(\'test\')' }],
12
+ invalid: [
13
+ {
14
+ code: invalid,
15
+ errors: [{ message: 'Found new Buffer' }]
16
+ }
17
+ ]
18
+ });
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-no-csrf-before-method-override';
7
+
8
+
9
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
10
+ valid: [{ code: 'express.methodOverride();express.csrf()' }],
11
+ invalid: [
12
+ {
13
+ code: 'express.csrf();express.methodOverride()',
14
+ errors: [{ message: 'express.csrf() middleware found before express.methodOverride()' }]
15
+ }
16
+ ]
17
+ });
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const invalid = 'var a = fs.open(c)';
7
+
8
+ const ruleName = 'detect-non-literal-fs-filename';
9
+
10
+
11
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
12
+ valid: [{ code: 'var a = fs.open(\'test\')' }],
13
+ invalid: [
14
+ {
15
+ code: invalid,
16
+ errors: [{ message: 'Found fs.open with non literal argument at index 0' }]
17
+ }
18
+ ]
19
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-non-literal-regexp';
7
+ const invalid = 'var a = new RegExp(c, \'i\')';
8
+
9
+
10
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
11
+ valid: [{ code: 'var a = new RegExp(\'ab+c\', \'i\')' }],
12
+ invalid: [
13
+ {
14
+ code: invalid,
15
+ errors: [{ message: 'Found non-literal argument to RegExp Constructor' }]
16
+ }
17
+ ]
18
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-non-literal-require';
7
+ const invalid = 'var a = require(c)';
8
+
9
+
10
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
11
+ valid: [{ code: 'var a = require(\'b\')' }],
12
+ invalid: [
13
+ {
14
+ code: invalid,
15
+ errors: [{ message: 'Found non-literal argument in require' }]
16
+ }
17
+ ]
18
+ });
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-object-injection';
7
+
8
+ const Rule = require(`../rules/${ruleName}`);
9
+
10
+ const valid = 'var a = {};';
11
+ // const invalidVariable = "TODO";
12
+ // const invalidFunction = "TODO";
13
+ const invalidGeneric = 'var a = {}; a[b] = 4';
14
+
15
+
16
+ // TODO
17
+ // tester.run(`${ruleName} (Variable Assigned to)`, Rule, {
18
+ // valid: [{ code: valid }],
19
+ // invalid: [
20
+ // {
21
+ // code: invalidVariable,
22
+ // errors: [{ message: 'Variable Assigned to Object Injection Sink' }]
23
+ // }
24
+ // ]
25
+ // });
26
+ //
27
+ //
28
+ // tester.run(`${ruleName} (Function)`, Rule, {
29
+ // valid: [{ code: valid }],
30
+ // invalid: [
31
+ // {
32
+ // code: invalidFunction,
33
+ // errors: [{ message: `Variable Assigned to Object Injection Sink: <input>: 1\n\t${invalidFunction}\n\n` }]
34
+ // }
35
+ // ]
36
+ // });
37
+
38
+
39
+ tester.run(`${ruleName} (Generic)`, Rule, {
40
+ valid: [{ code: valid }],
41
+ invalid: [
42
+ {
43
+ code: invalidGeneric,
44
+ errors: [{ message: 'Generic Object Injection Sink' }]
45
+ }
46
+ ]
47
+ });
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-possible-timing-attacks';
7
+ const Rule = require(`../rules/${ruleName}`);
8
+
9
+ const valid = 'if (age === 5) {}';
10
+ const invalidLeft = 'if (password === \'mypass\') {}';
11
+ const invalidRigth = 'if (\'mypass\' === password) {}';
12
+
13
+
14
+ // We only check with one string "password" and operator "==="
15
+ // to KISS.
16
+
17
+ tester.run(`${ruleName} (left side)`, Rule, {
18
+ valid: [{ code: valid }],
19
+ invalid: [
20
+ {
21
+ code: invalidLeft,
22
+ errors: [{ message: 'Potential timing attack, left side: true' }]
23
+ }
24
+ ]
25
+ });
26
+
27
+
28
+ tester.run(`${ruleName} (right side)`, Rule, {
29
+ valid: [{ code: valid }],
30
+ invalid: [
31
+ {
32
+ code: invalidRigth,
33
+ errors: [{ message: 'Potential timing attack, right side: true' }]
34
+ }
35
+ ]
36
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-pseudoRandomBytes';
7
+ const invalid = 'crypto.pseudoRandomBytes';
8
+
9
+
10
+ tester.run(ruleName, require(`../rules/${ruleName}`), {
11
+ valid: [{ code: 'crypto.randomBytes' }],
12
+ invalid: [
13
+ {
14
+ code: invalid,
15
+ errors: [{ message: 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers' }]
16
+ }
17
+ ]
18
+ });
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const RuleTester = require('eslint').RuleTester;
4
+ const tester = new RuleTester();
5
+
6
+ const ruleName = 'detect-unsafe-regex';
7
+ const Rule = require(`../rules/${ruleName}`);
8
+
9
+
10
+ tester.run(ruleName, Rule, {
11
+ valid: [{ code: '/^\d+1337\d+$/' }],
12
+ invalid: [
13
+ {
14
+ code: '/(x+x+)+y/',
15
+ errors: [{ message: 'Unsafe Regular Expression' }]
16
+ }
17
+ ]
18
+ });
19
+
20
+
21
+ tester.run(`${ruleName} (new RegExp)`, Rule, {
22
+ valid: [{ code: 'new RegExp(\'^\d+1337\d+$\')' }],
23
+ invalid: [
24
+ {
25
+ code: 'new RegExp(\'x+x+)+y\')',
26
+ errors: [{ message: 'Unsafe Regular Expression (new RegExp)' }]
27
+ }
28
+ ]
29
+ });