Skip to content

Commit 78292e0

Browse files
committed
chore: Clean up source code formatting
Fixes #4 Closes #78
1 parent 0a6631e commit 78292e0

38 files changed

+429
-330
lines changed

.eslintrc

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
{
2-
"extends": "nodesecurity"
2+
"extends": [
3+
"eslint:recommended",
4+
"prettier"
5+
],
6+
"parserOptions": {
7+
"ecmaVersion": "latest"
8+
},
9+
"env": {
10+
"node": true,
11+
"es2020": true
12+
}
313
}

.github/workflows/ci.yml

+26-26
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,38 @@ jobs:
1010
name: Lint
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v2
14-
- uses: actions/setup-node@v2
15-
with:
16-
node-version: '16.x'
17-
18-
- name: Install Packages
19-
run: npm install
20-
21-
- name: Lint Files
22-
run: npm run lint
13+
- uses: actions/checkout@v2
14+
- uses: actions/setup-node@v2
15+
with:
16+
node-version: '16.x'
17+
18+
- name: Install Packages
19+
run: npm install
20+
21+
- name: Lint Files
22+
run: npm run lint
2323

2424
test:
2525
name: Test
2626
strategy:
2727
matrix:
2828
os: [ubuntu-latest]
29-
node: [17.x, 16.x, 14.x, 12.x, "12.22.0"]
29+
node: [17.x, 16.x, 14.x, 12.x, '12.22.0']
3030
include:
31-
- os: windows-latest
32-
node: "16.x"
33-
- os: macOS-latest
34-
node: "16.x"
31+
- os: windows-latest
32+
node: '16.x'
33+
- os: macOS-latest
34+
node: '16.x'
3535
runs-on: ${{ matrix.os }}
3636
steps:
37-
- uses: actions/checkout@v2
38-
39-
- uses: actions/setup-node@v2
40-
with:
41-
node-version: ${{ matrix.node }}
42-
43-
- name: Install Packages
44-
run: npm install
45-
46-
- name: Test
47-
run: npm test
37+
- uses: actions/checkout@v2
38+
39+
- uses: actions/setup-node@v2
40+
with:
41+
node-version: ${{ matrix.node }}
42+
43+
- name: Install Packages
44+
run: npm install
45+
46+
- name: Test
47+
run: npm test

.prettierrc.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"trailingComma": "es5",
3+
"tabWidth": 2,
4+
"semi": true,
5+
"singleQuote": true,
6+
"printWidth": 180
7+
}

CHANGELOG.md

+29-34
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
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
1+
# 1.4.0 / 2017-06-12
2+
3+
- Add recommended ruleset to the usage example
4+
- Removes filenames from error output
5+
6+
# 1.3.0 / 2017-02-09
7+
8+
- README.md - document detect-disable-mustache-escape rule
9+
- README.md - documentation detect-new-buffer rule
10+
- Fixed crash with `detect-no-csrf-before-method-override` rule.
11+
- Style guide applied to all the code involving the tests
12+
- Removing a repeated test and style changes
13+
- ESLint added to the workflow
14+
- Removed not needed variables
15+
- Fix to a problem with a rule detected implementing the tests
16+
- Test engine with tests for all the rules
17+
- Add additional information to README for each rule
18+
19+
# 1.2.0 / 2016-01-21
20+
21+
- updated to check for new RegExp too
22+
23+
# 1.1.0 / 2016-01-06
24+
25+
- adding eslint rule to detect new buffer hotspot
26+
27+
# 1.0.0 / 2015-11-15
28+
29+
- rules disabled by default

README.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,19 @@ Add the following to your `.eslintrc` file:
1818
]
1919
```
2020

21-
2221
## Developer guide
2322

2423
- Use [GitHub pull requests](https://help.github.com/articles/using-pull-requests).
2524
- Conventions:
26-
- We use our [custom ESLint setup](https://github.com/nodesecurity/eslint-config-nodesecurity).
27-
- 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:
28-
```sh
29-
npm run-script cont-int
30-
```
25+
- We use our [custom ESLint setup](https://github.com/nodesecurity/eslint-config-nodesecurity).
26+
- 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:
27+
28+
```sh
29+
npm run-script cont-int
30+
```
3131

3232
### Tests
33+
3334
```sh
3435
npm test
3536
```
@@ -58,7 +59,7 @@ More information: [Avoiding Command Injection in Node.js](docs/avoid-command-inj
5859

5960
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.
6061

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

6364
#### `detect-eval-with-expression`
6465

docs/avoid-command-injection-node.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ child_process.exec('ls', function (err, data) {
1515
What happens though when you need to start getting user input for arguments into your command? The obvious solution is to take the user input and build your command out using string concatenation. But here's something I've learned over the years: When you use string concatenation to send data from one system to another you're probably going to have a bad day.
1616

1717
```js
18-
var path = "user input";
18+
var path = 'user input';
1919
child_process.exec('ls -l ' + path, function (err, data) {
2020
console.log(data);
2121
});
2222
```
2323

2424
## Why is string concatenation a problem?
2525

26-
Well, because under the hood, `child_process.exec` makes a call to execute <kbd>/bin/sh</kbd> rather than the target program. The command that was sent just gets passed along as a shell command in the newly spawned <kbd>/bin/sh</kbd> process. `child_process.exec` has a misleading name - it's a bash interpreter, not a program launcher. And that means that all shell metacharacters can have devastating effects if the command is including user input.
26+
Well, because under the hood, `child_process.exec` makes a call to execute <kbd>/bin/sh</kbd> rather than the target program. The command that was sent just gets passed along as a shell command in the newly spawned <kbd>/bin/sh</kbd> process. `child_process.exec` has a misleading name - it's a bash interpreter, not a program launcher. And that means that all shell metacharacters can have devastating effects if the command is including user input.
2727

2828
```sh
2929
[pid 25170] execve("/bin/sh", ["/bin/sh", "-c", "ls -l user input"], [/* 16 vars */]
@@ -42,9 +42,9 @@ Let's modify our example to use `execFile` and `spawn` and see how the system ca
4242
```js
4343
var child_process = require('child_process');
4444

45-
var path = "."
45+
var path = '.';
4646
child_process.execFile('/bin/ls', ['-l', path], function (err, result) {
47-
console.log(result)
47+
console.log(result);
4848
});
4949
```
5050
@@ -61,8 +61,8 @@ Similar example using `spawn` instead.
6161
```js
6262
var child_process = require('child_process');
6363

64-
var path = "."
65-
var ls = child_process.spawn('/bin/ls', ['-l', path])
64+
var path = '.';
65+
var ls = child_process.spawn('/bin/ls', ['-l', path]);
6666
ls.stdout.on('data', function (data) {
6767
console.log(data.toString());
6868
});
@@ -80,6 +80,6 @@ This does however come with a caveat: using `spawn` or `execFile` is not always
8080
8181
So, here's the collective guidance for running system commands from node.js:
8282
83-
* Avoid using `child_process.exec`, and never use it if the command contains any input that changes based on user input.
84-
* Try to avoid letting users pass in options to commands if possible. Typically values are okay when using spawn or execfile, but selecting options via a user controlled string is a bad idea.
85-
* If you must allow for user controlled options, look at the options for the command extensively, determine which options are safe, and whitelist only those options.
83+
- Avoid using `child_process.exec`, and never use it if the command contains any input that changes based on user input.
84+
- Try to avoid letting users pass in options to commands if possible. Typically values are okay when using spawn or execfile, but selecting options via a user controlled string is a bad idea.
85+
- If you must allow for user controlled options, look at the options for the command extensively, determine which options are safe, and whitelist only those options.

docs/regular-expression-dos-and-node.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
Imagine you are trying to buy a ticket to your favorite JavaScript conference, and instead of getting the ticket page, you instead get `500 Internal Server Error`. For some reason the site is down. You can't do the thing that you want to do most and the conference is losing out on your purchase, all because the application is unavailable.
44

5-
Availability is not often treated as a security problem, which it is, and it's impacts are immediate, and deeply felt.
5+
Availability is not often treated as a security problem, which it is, and it's impacts are immediate, and deeply felt.
66

77
The attack surface for Node.js in regards to loss of availability is quite large, as we are dealing with a single event loop. If an attacker can control and block that event loop, then nothing else gets done.
88

99
There are many ways to block the event loop, one way an attacker can do that is with [Regular Expression Denial of Service (ReDoS)](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).
1010

11-
If user provided input finds it's way into a regular expression, or a regular expression is designed with certain attributes, such as grouping with repetition, you can find yourself in a vulnerable position, as the regular expression match could take a long time to process. [OWASP](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) has a deeper explanation of why this occurs.
11+
If user provided input finds it's way into a regular expression, or a regular expression is designed with certain attributes, such as grouping with repetition, you can find yourself in a vulnerable position, as the regular expression match could take a long time to process. [OWASP](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) has a deeper explanation of why this occurs.
1212

1313
Let's look at an vulnerable example. Below we are attempting the common task of validating an email address on the server.
1414

@@ -24,19 +24,19 @@ With the example above, we can use this test script to show how bad input can im
2424

2525
```js
2626
start = process.hrtime();
27-
console.log(validateEmailFormat("[email protected]"));
27+
console.log(validateEmailFormat('[email protected]'));
2828
console.log(process.hrtime(start));
2929

3030
start = process.hrtime();
31-
console.log(validateEmailFormat("jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.5555555555555555555555555555555555555555{"));
31+
console.log(validateEmailFormat('jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.5555555555555555555555555555555555555555{'));
3232
console.log(process.hrtime(start));
3333

3434
start = process.hrtime();
35-
console.log(validateEmailFormat("jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.55555555555555555555555555555555555555555{"));
35+
console.log(validateEmailFormat('jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.55555555555555555555555555555555555555555{'));
3636
console.log(process.hrtime(start));
3737

3838
start = process.hrtime();
39-
console.log(validateEmailFormat("jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.555555555555555555555555555555555555555555555555555555{"));
39+
console.log(validateEmailFormat('jjjjjjjjjjjjjjjjjjjjjjjjjjjj@ccccccccccccccccccccccccccccc.555555555555555555555555555555555555555555555555555555{'));
4040
console.log(process.hrtime(start));
4141
```
4242

@@ -59,21 +59,21 @@ Here is a rule for eslint that you can use to test your JavaScript regular expre
5959

6060
```js
6161
var safe = require('safe-regex');
62-
module.exports = function(context) {
63-
"use strict";
62+
module.exports = function (context) {
63+
'use strict';
6464

6565
return {
66-
"Literal": function(node) {
66+
Literal: function (node) {
6767
var token = context.getTokens(node)[0],
68-
nodeType = token.type,
69-
nodeValue = token.value;
68+
nodeType = token.type,
69+
nodeValue = token.value;
7070

71-
if (nodeType === "RegularExpression") {
71+
if (nodeType === 'RegularExpression') {
7272
if (!safe(nodeValue)) {
73-
context.report(node, "Possible Unsafe Regular Expression");
73+
context.report(node, 'Possible Unsafe Regular Expression');
7474
}
7575
}
76-
}
76+
},
7777
};
7878
};
7979
```

docs/the-dangers-of-square-bracket-notation.md

+17-26
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,33 @@ We are going to be looking at some peculiar and potentially dangerous implicatio
44

55
Square bracket notation for objects in JavaScript provides a very convenient way to dynamically access a specific property or method based on the contents of a variable. The end result of this feature is something that is very similar to Ruby's Mass Assignment: Given an object, you are able to dynamically assign and retrieve properties of this object without specifying this property should be accessible.
66

7-
*Note: These examples are simple, and seemingly obvious - we will take a look at that later. For now, disregard the practicality of the examples and focus on the dangerous patterns that they reveal.*
7+
_Note: These examples are simple, and seemingly obvious - we will take a look at that later. For now, disregard the practicality of the examples and focus on the dangerous patterns that they reveal._
88

99
Let's take a look at why this could be a problem.
1010

1111
### Issue #1: Bracket object notation with user input grants access to every property available on the object.
1212

1313
```js
14-
exampleClass[userInput[1]] = userInput[2]
14+
exampleClass[userInput[1]] = userInput[2];
1515
```
1616

1717
I won't spend much time here, as I believe this is fairly well known. If exampleClass contains a sensitive property, the above code will allow it to be edited.
1818

19-
### Issue #2: Bracket object notation with user input grants access to every property available on the object, __*including prototypes.*__
19+
### Issue #2: Bracket object notation with user input grants access to every property available on the object, **_including prototypes._**
2020

2121
```js
22-
userInput = [
23-
'constructor',
24-
'{}'
25-
]
26-
exampleClass[userInput[1]] = userInput[2]
22+
userInput = ['constructor', '{}'];
23+
exampleClass[userInput[1]] = userInput[2];
2724
```
2825

29-
This looks pretty innocuous, even if it is an uncommon pattern. The problem here is that we can access or overwrite prototypes such as `constructor` or `__defineGetter__`, which may be used later on. The most likely outcome of this scenario would be an application crash, when a string is attempted to be called as a function.
26+
This looks pretty innocuous, even if it is an uncommon pattern. The problem here is that we can access or overwrite prototypes such as `constructor` or `__defineGetter__`, which may be used later on. The most likely outcome of this scenario would be an application crash, when a string is attempted to be called as a function.
3027

31-
### Issue #3: Bracket object notation with user input grants access to every property available on the object, including prototypes, __*which can lead to Remote Code Execution.*__
28+
### Issue #3: Bracket object notation with user input grants access to every property available on the object, including prototypes, **_which can lead to Remote Code Execution._**
3229

3330
Now here's where things get really dangerous. It's also where example code gets really implausible - bear with me.
3431

3532
```js
36-
var user = function() {
33+
var user = function () {
3734
this.name = 'jon';
3835
//An empty user constructor.
3936
};
@@ -44,24 +41,18 @@ function handler(userInput) {
4441
}
4542
```
4643

47-
In the previous section, I mentioned that constructor can be accessed from square brackets. In this case, since we are dealing with a function, the constructor we get back is the `Function` Constructor, which compiles a string of code into a function.
44+
In the previous section, I mentioned that constructor can be accessed from square brackets. In this case, since we are dealing with a function, the constructor we get back is the `Function` Constructor, which compiles a string of code into a function.
4845

4946
### Exploitation:
5047

51-
In order to exploit the above code, we need a two stage exploit function.
48+
In order to exploit the above code, we need a two stage exploit function.
5249

5350
```js
54-
function exploit(cmd){
55-
var userInputStageOne = [
56-
'constructor',
57-
'require("child_process").exec(arguments[0],console.log)'
58-
];
59-
var userInputStageTwo = [
60-
'anyVal',
61-
cmd
62-
];
63-
64-
handler(userInputStageOne);
51+
function exploit(cmd) {
52+
var userInputStageOne = ['constructor', 'require("child_process").exec(arguments[0],console.log)'];
53+
var userInputStageTwo = ['anyVal', cmd];
54+
55+
handler(userInputStageOne);
6556
handler(userInputStageTwo);
6657
}
6758
```
@@ -80,8 +71,8 @@ user['anyVal'] = user['constructor'](userInput[1]);
8071
Executing this code creates a function containing the payload, and assigns it to `user['anyVal']`:
8172

8273
```js
83-
user['anyVal'] = function() {
84-
require("child_process").exec(arguments[0],console.log)
74+
user['anyVal'] = function () {
75+
require('child_process').exec(arguments[0], console.log);
8576
};
8677
```
8778

0 commit comments

Comments
 (0)