Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add meta object documentation for all rules. Closes #48 #79

Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
.idea
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,27 @@ More information: [Regular Expression DoS and Node.js](docs/regular-expression-d

#### `detect-buffer-noassert`

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

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`."

#### `detect-child-process`

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)
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)

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

#### `detect-disable-mustache-escape`

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.

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

#### `detect-eval-with-expression`

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

More information: http://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript
More information: [stack-exchange post](http://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript)
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved

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

Expand All @@ -79,7 +79,7 @@ More information: [Bypass Connect CSRF protection by abusing methodOverride Midd

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

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

#### `detect-non-literal-regexp`

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

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

More information: http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm
More information: [Require Blogpost](http://www.bennadel.com/blog/2169-where-does-node-js-and-require-look-for-modules.htm)
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved

#### `detect-object-injection`

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

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

More information: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/
More information: [Snyk Blogpost; possbily flawed.](https://snyk.io/blog/node-js-timing-attack-ccc-ctf/)
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved

#### `detect-pseudoRandomBytes`

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

More information: http://stackoverflow.com/questions/18130254/randombytes-vs-pseudorandombytes
More information: [Stackoverflow Post](http://stackoverflow.com/questions/18130254/randombytes-vs-pseudorandombytes)
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved

#### `detect-new-buffer`

Detect instances of new Buffer(argument) where argument is any non-literal value.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 58 additions & 50 deletions rules/detect-buffer-noassert.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,59 +11,67 @@

const names = [];

module.exports = function(context) {

const read = [
'readUInt8',
'readUInt16LE',
'readUInt16BE',
'readUInt32LE',
'readUInt32BE',
'readInt8',
'readInt16LE',
'readInt16BE',
'readInt32LE',
'readInt32BE',
'readFloatLE',
'readFloatBE',
'readDoubleL',
'readDoubleBE'
];
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Detect calls to "buffer" with `noAssert` flag set. 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`."',
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://nodejs.org/api/buffer.html'
MarkKragerup marked this conversation as resolved.
Show resolved Hide resolved
}
},
create: function(context) {
const read = [
'readUInt8',
'readUInt16LE',
'readUInt16BE',
'readUInt32LE',
'readUInt32BE',
'readInt8',
'readInt16LE',
'readInt16BE',
'readInt32LE',
'readInt32BE',
'readFloatLE',
'readFloatBE',
'readDoubleL',
'readDoubleBE'
];

const write = [
'writeUInt8',
'writeUInt16LE',
'writeUInt16BE',
'writeUInt32LE',
'writeUInt32BE',
'writeInt8',
'writeInt16LE',
'writeInt16BE',
'writeInt32LE',
'writeInt32BE',
'writeFloatLE',
'writeFloatBE',
'writeDoubleLE',
'writeDoubleBE'
];
const write = [
'writeUInt8',
'writeUInt16LE',
'writeUInt16BE',
'writeUInt32LE',
'writeUInt32BE',
'writeInt8',
'writeInt16LE',
'writeInt16BE',
'writeInt32LE',
'writeInt32BE',
'writeFloatLE',
'writeFloatBE',
'writeDoubleLE',
'writeDoubleBE'
];

return {
'MemberExpression': function (node) {
let index;
if (read.indexOf(node.property.name) !== -1) {
index = 1;
}
else if (write.indexOf(node.property.name) !== -1) {
index = 2;
}
return {
'MemberExpression': function(node) {
let index;
if (read.indexOf(node.property.name) !== -1) {
index = 1;
}
else if (write.indexOf(node.property.name) !== -1) {
index = 2;
}

if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
const token = context.getTokens(node)[0];
return context.report(node, `Found Buffer.${ node.property.name } with noAssert flag set true`);
if (index && node.parent && node.parent.arguments && node.parent.arguments[index] && node.parent.arguments[index].value) {
const token = context.getTokens(node)[0];
return context.report(node, `Found Buffer.${node.property.name} with noAssert flag set true`);

}
}
}

};

};
}
};
57 changes: 33 additions & 24 deletions rules/detect-child-process.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,42 @@

const names = [];

module.exports = function(context) {

return {
'CallExpression': function (node) {
const token = context.getTokens(node)[0];
if (node.callee.name === 'require') {
const args = node.arguments[0];
if (args && args.type === 'Literal' && args.value === 'child_process') {
if (node.parent.type === 'VariableDeclarator') {
names.push(node.parent.id.name);
}
else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
names.push(node.parent.left.name);
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: '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).',
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://github.com/nodesecurity/eslint-plugin-security/blob/main/docs/avoid-command-injection-node.md'
}
},
create: function(context) {
return {
'CallExpression': function(node) {
const token = context.getTokens(node)[0];
if (node.callee.name === 'require') {
const args = node.arguments[0];
if (args && args.type === 'Literal' && args.value === 'child_process') {
if (node.parent.type === 'VariableDeclarator') {
names.push(node.parent.id.name);
}
else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
names.push(node.parent.left.name);
}
return context.report(node, 'Found require("child_process")');
}
return context.report(node, 'Found require("child_process")');
}
}
},
'MemberExpression': function (node) {
const token = context.getTokens(node)[0];
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
return context.report(node, 'Found child_process.exec() with non Literal first argument');
},
'MemberExpression': function(node) {
const token = context.getTokens(node)[0];
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
if (node.parent && node.parent.arguments && node.parent.arguments[0].type !== 'Literal') {
return context.report(node, 'Found child_process.exec() with non Literal first argument');
}
}
}
}

};

};
}
};
34 changes: 21 additions & 13 deletions rules/detect-disable-mustache-escape.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@

'use strict';

module.exports = function(context) {

return {
'AssignmentExpression': function(node) {
if (node.operator === '=') {
if (node.left.property) {
if (node.left.property.name === 'escapeMarkup') {
if (node.right.value === false) {
context.report(node, 'Markup escaping disabled.');
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: '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.',
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)'
}
},
create: function(context) {
return {
'AssignmentExpression': function(node) {
if (node.operator === '=') {
if (node.left.property) {
if (node.left.property.name === 'escapeMarkup') {
if (node.right.value === false) {
context.report(node, 'Markup escaping disabled.');
}
}
}
}
}
}
};

};
}
};
26 changes: 18 additions & 8 deletions rules/detect-eval-with-expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,23 @@
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

return {
'CallExpression': function(node) {
if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
context.report(node, `eval with argument of type ${ node.arguments[0].type}`);
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Detects `eval(variable)` which can allow an attacker to run arbitrary code inside your process.',
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://security.stackexchange.com/questions/94017/what-are-the-security-issues-with-eval-in-javascript'
}
};
},
create: function(context) {
return {
'CallExpression': function(node) {
if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
context.report(node, `eval with argument of type ${node.arguments[0].type}`);
}
}
};
}
};
31 changes: 18 additions & 13 deletions rules/detect-new-buffer.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
'use strict';


module.exports = function (context) {
// Detects instances of new Buffer(argument)
// where argument is any non literal value.
return {
'NewExpression': function (node) {
if (node.callee.name === 'Buffer' &&
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Detect instances of new Buffer(argument) where argument is any non-literal value.',
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://github.com/nodesecurity/eslint-plugin-security/blob/main/README.md'
}
},
create: function(context) {
return {
'NewExpression': function(node) {
if (node.callee.name === 'Buffer' &&
node.arguments[0] &&
node.arguments[0].type !== 'Literal') {

return context.report(node, 'Found new Buffer');
return context.report(node, 'Found new Buffer');
}
}



}
};

};
}
};