Skip to content

Commit d913b9e

Browse files
author
Adam Baldwin
authored
Merge pull request #3 from jesusprubio/master
A bit of love
2 parents c681aa7 + 389de0d commit d913b9e

22 files changed

+352
-10
lines changed

.eslintrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "nodesecurity"
3+
}

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Add the following to your `.eslintrc` file:
1616
"security"
1717
]
1818
```
19+
1920
### Rules
2021

2122
- `detect-unsafe-regex` - Locates potentially unsafe regular expressions
@@ -31,3 +32,18 @@ Add the following to your `.eslintrc` file:
3132
- `detect-possible-timing-attacks` - Detects insecure comparisons (== != !== ===)
3233
- `detect-pseudoRandomBytes` - Detects if pseudoRandomBytes() is in use
3334

35+
36+
## Developer guide
37+
38+
- Use [GitHub pull requests](https://help.github.com/articles/using-pull-requests).
39+
- Conventions:
40+
- We use our [custom ESLint setup](https://github.com/nodesecurity/eslint-config-nodesecurity).
41+
- 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:
42+
```sh
43+
npm run-script cont-int
44+
```
45+
46+
### Tests
47+
```sh
48+
npm test
49+
```

package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"description": "Security rules for eslint",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "./node_modules/.bin/mocha test/**/*",
8+
"lint": "./node_modules/.bin/eslint .",
9+
"cont-int": "npm test && npm run-script lint"
810
},
911
"repository": {
1012
"type": "git",
@@ -25,6 +27,8 @@
2527
"safe-regex": "^1.1.0"
2628
},
2729
"devDependencies": {
28-
"eslint": "^1.8.0"
30+
"eslint": "^2.10.1",
31+
"eslint-config-nodesecurity": "^1.3.1",
32+
"mocha": "^2.4.5"
2933
}
3034
}

rules/detect-buffer-noassert.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ module.exports = function(context) {
6363

6464
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
6565
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));
66+
return context.report(node, 'Found Buffer.' + node.property.name + ' with noAssert flag set true:\n\t' + getSource(token));
6767

6868
}
6969
}

rules/detect-child-process.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ module.exports = function(context) {
2828
} else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
2929
names.push(node.parent.left.name);
3030
}
31-
return context.report(node, 'found require("child_process")\n\t' + getSource(token));
31+
return context.report(node, 'Found require("child_process")\n\t' + getSource(token));
3232
}
3333
}
3434
},
3535
"MemberExpression": function (node) {
3636
var token = context.getTokens(node)[0];
3737
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
3838
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));
39+
return context.report(node, 'Found child_process.exec() with non Literal first argument\n\t' + getSource(token));
4040
}
4141
}
4242
}

rules/detect-non-literal-fs-filename.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module.exports = function(context) {
3636

3737
if (result.length > 0) {
3838
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));
39+
return context.report(node, 'Found fs.' + node.property.name + ' with non literal argument at index ' + result.join(',') + '\n\t' + getSource(token));
4040
}
4141

4242

rules/detect-non-literal-regexp.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ module.exports = function(context) {
1616
return token.loc.start.line + ': ' + context.getSourceLines().slice(token.loc.start.line - 1, token.loc.end.line).join('\n\t');
1717
}
1818
return {
19-
"CallExpression": function(node) {
19+
"NewExpression": function(node) {
2020
if (node.callee.name === 'RegExp') {
2121
var args = node.arguments;
2222
if (args && args.length > 0 && args[0].type !== 'Literal') {
2323
var token = context.getTokens(node)[0];
24-
return context.report(node, 'found non-literal argument to RegExp Constructor\n\t' + getSource(token));
24+
return context.report(node, 'Found non-literal argument to RegExp Constructor\n\t' + getSource(token));
2525
}
2626
}
2727

rules/detect-non-literal-require.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ module.exports = function(context) {
2121
var args = node.arguments;
2222
if (args && args.length > 0 && args[0].type !== 'Literal') {
2323
var token = context.getTokens(node)[0];
24-
return context.report(node, 'found non-literal argument in require\n\t' + getSource(token));
24+
return context.report(node, 'Found non-literal argument in require\n\t' + getSource(token));
2525
}
2626
}
2727

rules/detect-pseudoRandomBytes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module.exports = function(context) {
1919
"MemberExpression": function (node) {
2020
if (node.property.name === 'pseudoRandomBytes') {
2121
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));
22+
return context.report(node, 'Found crypto.pseudoRandomBytes which does not produce cryptographically strong numbers:\n\t' + getSource(token));
2323
}
2424
}
2525

test/detect-buffer-noassert.js

+30
Original file line numberDiff line numberDiff line change
@@ -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:\n\t1: ${invalid}` }]
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:\n\t1: ${invalid}` }]
28+
}
29+
]
30+
});

test/detect-child-process.js

+35
Original file line numberDiff line numberDiff line change
@@ -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")\n\t1: ${invalidRequire}` }]
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")\n\t1: ${invalidExec}` },
32+
{ message: `Found child_process.exec() with non Literal first argument\n\t1: ${invalidExec}` }]
33+
}
34+
]
35+
});
+17
Original file line numberDiff line numberDiff line change
@@ -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+
});

test/detect-eval-with-expression.js

+17
Original file line numberDiff line numberDiff line change
@@ -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+
});

test/detect-new-buffer.js

+18
Original file line numberDiff line numberDiff line change
@@ -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\n\t1: ${invalid}` }]
16+
}
17+
]
18+
});
Original file line numberDiff line numberDiff line change
@@ -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+
});
+19
Original file line numberDiff line numberDiff line change
@@ -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\n\t1: ${invalid}` }]
17+
}
18+
]
19+
});

test/detect-non-literal-regexp.js

+18
Original file line numberDiff line numberDiff line change
@@ -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\n\t1: ${invalid}` }]
16+
}
17+
]
18+
});

test/detect-non-literal-require.js

+18
Original file line numberDiff line numberDiff line change
@@ -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\n\t1: ${invalid}` }]
16+
}
17+
]
18+
});

test/detect-object-injection.js

+47
Original file line numberDiff line numberDiff line change
@@ -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: <input>: 1\n\t${invalidVariable}\n\n` }]
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: <input>: 1\n\t${invalidGeneric}\n\n` }]
45+
}
46+
]
47+
});

0 commit comments

Comments
 (0)