eslint-plugin-security 1.6.0 → 1.7.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/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/CHANGELOG.md
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.0](https://www.github.com/eslint-community/eslint-plugin-security/compare/v1.6.0...v1.7.0) (2023-01-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* improve detect-child-process rule ([#108](https://www.github.com/eslint-community/eslint-plugin-security/issues/108)) ([64ae529](https://www.github.com/eslint-community/eslint-plugin-security/commit/64ae52944a86f9d9daee769acd63ebbdfc5b6631))
|
|
9
|
+
|
|
3
10
|
## [1.6.0](https://www.github.com/eslint-community/eslint-plugin-security/compare/v1.5.0...v1.6.0) (2023-01-11)
|
|
4
11
|
|
|
5
12
|
### Features
|
|
@@ -21,25 +28,25 @@
|
|
|
21
28
|
## 1.5.0 / 2022-04-14
|
|
22
29
|
|
|
23
30
|
- Fix avoid crash when exec() is passed no arguments
|
|
24
|
-
Closes [#82](https://github.com/
|
|
31
|
+
Closes [#82](https://github.com/eslint-community/eslint-plugin-security/pull/82) with ref as [#23](https://github.com/eslint-community/eslint-plugin-security/pull/23)
|
|
25
32
|
- Fix incorrect method name in detect-buffer-noassert
|
|
26
|
-
Closes [#63](https://github.com/
|
|
33
|
+
Closes [#63](https://github.com/eslint-community/eslint-plugin-security/pull/63) and [#80](https://github.com/eslint-community/eslint-plugin-security/pull/80)
|
|
27
34
|
- Clean up source code formatting
|
|
28
|
-
Fixes [#4](https://github.com/
|
|
35
|
+
Fixes [#4](https://github.com/eslint-community/eslint-plugin-security/issues/4) and closes [#78](https://github.com/eslint-community/eslint-plugin-security/pull/78)
|
|
29
36
|
- Add release script
|
|
30
|
-
[Script](https://github.com/
|
|
31
|
-
- Add non-literal require TemplateLiteral support [#81](https://github.com/
|
|
32
|
-
- Add meta object documentation for all rules [#79](https://github.com/
|
|
37
|
+
[Script](https://github.com/eslint-community/eslint-plugin-security/commit/0a6631ea448eb0031af7b351c85b3aa298c2e44c)
|
|
38
|
+
- Add non-literal require TemplateLiteral support [#81](https://github.com/eslint-community/eslint-plugin-security/pull/81)
|
|
39
|
+
- Add meta object documentation for all rules [#79](https://github.com/eslint-community/eslint-plugin-security/pull/79)
|
|
33
40
|
- Added Git pre-commit hook to format JS files
|
|
34
|
-
[Pre-commit hook](https://github.com/
|
|
41
|
+
[Pre-commit hook](https://github.com/eslint-community/eslint-plugin-security/commit/e2ae2ee9ef214ca6d8f69fbcc438d230fda2bf97)
|
|
35
42
|
- Added yarn installation method
|
|
36
43
|
- Fix linting errors and step
|
|
37
|
-
[Lint errors](https://github.com/
|
|
44
|
+
[Lint errors](https://github.com/eslint-community/eslint-plugin-security/commit/1258118c2d07722e9fb388a672b287bb43bc73b3), [Lint step](https://github.com/eslint-community/eslint-plugin-security/commit/84f3ed3ab88427753c7ac047d0bccbe557f28aa5)
|
|
38
45
|
- Create workflows
|
|
39
46
|
Check commit message on pull requests, Set up ci on main branch
|
|
40
47
|
- Update test and lint commands to work cross-platform
|
|
41
|
-
[Commit](https://github.com/
|
|
42
|
-
- Merge pull request [#47](https://github.com/
|
|
48
|
+
[Commit](https://github.com/eslint-community/eslint-plugin-security/commit/d3d8e7a27894aa3f83b560f530eb49750e9ee19a)
|
|
49
|
+
- Merge pull request [#47](https://github.com/eslint-community/eslint-plugin-security/pull/47) from pdehaan/add-docs
|
|
43
50
|
Add old liftsecurity blog posts to docs/ folder
|
|
44
51
|
- Bumped up dependencies
|
|
45
52
|
- Added `package-lock.json`
|
|
@@ -50,19 +57,19 @@
|
|
|
50
57
|
|
|
51
58
|
- 1.4.0
|
|
52
59
|
- Stuff and things for 1.4.0 beep boop 🤖
|
|
53
|
-
- Merge pull request [#14](https://github.com/
|
|
60
|
+
- Merge pull request [#14](https://github.com/eslint-community/eslint-plugin-security/issues/14) from travi/recommended-example
|
|
54
61
|
Add recommended ruleset to the usage example
|
|
55
|
-
- Merge pull request [#19](https://github.com/
|
|
62
|
+
- Merge pull request [#19](https://github.com/eslint-community/eslint-plugin-security/issues/19) from pdehaan/add-changelog
|
|
56
63
|
Add basic CHANGELOG.md file
|
|
57
|
-
- Merge pull request [#17](https://github.com/
|
|
64
|
+
- Merge pull request [#17](https://github.com/eslint-community/eslint-plugin-security/issues/17) from pdehaan/issue-16
|
|
58
65
|
Remove filename from error output
|
|
59
66
|
- Add basic CHANGELOG.md file
|
|
60
67
|
- Remove filename from error output
|
|
61
68
|
- Add recommended ruleset to the usage example
|
|
62
|
-
for [#9](https://github.com/
|
|
63
|
-
- Merge pull request [#10](https://github.com/
|
|
69
|
+
for [#9](https://github.com/eslint-community/eslint-plugin-security/issues/9)
|
|
70
|
+
- Merge pull request [#10](https://github.com/eslint-community/eslint-plugin-security/issues/10) from pdehaan/issue-9
|
|
64
71
|
Add 'plugin:security/recommended' config to plugin
|
|
65
|
-
- Merge pull request [#12](https://github.com/
|
|
72
|
+
- Merge pull request [#12](https://github.com/eslint-community/eslint-plugin-security/issues/12) from tupaschoal/patch-1
|
|
66
73
|
Fix broken link for detect-object-injection
|
|
67
74
|
- Fix broken link for detect-object-injection
|
|
68
75
|
The current link leads to a 404 page, the new one is the proper page.
|
|
@@ -73,15 +80,15 @@
|
|
|
73
80
|
- 1.3.0
|
|
74
81
|
- Merge branch 'scottnonnenberg-update-docs'
|
|
75
82
|
- Fix merge conflicts because I can't figure out how to accept pr's in the right order
|
|
76
|
-
- Merge pull request [#7](https://github.com/
|
|
83
|
+
- Merge pull request [#7](https://github.com/eslint-community/eslint-plugin-security/issues/7) from HamletDRC/patch-1
|
|
77
84
|
README.md - documentation detect-new-buffer rule
|
|
78
|
-
- Merge pull request [#8](https://github.com/
|
|
85
|
+
- Merge pull request [#8](https://github.com/eslint-community/eslint-plugin-security/issues/8) from HamletDRC/patch-2
|
|
79
86
|
README.md - document detect-disable-mustache-escape rule
|
|
80
|
-
- Merge pull request [#3](https://github.com/
|
|
87
|
+
- Merge pull request [#3](https://github.com/eslint-community/eslint-plugin-security/issues/3) from jesusprubio/master
|
|
81
88
|
A bit of love
|
|
82
89
|
- README.md - document detect-disable-mustache-escape rule
|
|
83
90
|
- README.md - documentation detect-new-buffer rule
|
|
84
|
-
- Merge pull request [#6](https://github.com/
|
|
91
|
+
- Merge pull request [#6](https://github.com/eslint-community/eslint-plugin-security/issues/6) from mathieumg/csrf-bug
|
|
85
92
|
Fixed crash with `detect-no-csrf-before-method-override` rule
|
|
86
93
|
- Fixed crash with `detect-no-csrf-before-method-override` rule.
|
|
87
94
|
- Finishing last commit
|
|
@@ -95,7 +102,6 @@
|
|
|
95
102
|
- A little bit of massage to readme intro
|
|
96
103
|
- Add additional information to README for each rule
|
|
97
104
|
|
|
98
|
-
|
|
99
105
|
## 1.2.0 / 2016-01-21
|
|
100
106
|
|
|
101
107
|
- 1.2.0
|
|
@@ -11,7 +11,7 @@ Let's take a look at why this could be a problem.
|
|
|
11
11
|
## Issue #1: Bracket object notation with user input grants access to every property available on the object
|
|
12
12
|
|
|
13
13
|
```js
|
|
14
|
-
exampleClass[userInput[
|
|
14
|
+
exampleClass[userInput[0]] = userInput[1];
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
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.
|
|
@@ -20,7 +20,7 @@ I won't spend much time here, as I believe this is fairly well known. If example
|
|
|
20
20
|
|
|
21
21
|
```js
|
|
22
22
|
userInput = ['constructor', '{}'];
|
|
23
|
-
exampleClass[userInput[
|
|
23
|
+
exampleClass[userInput[0]] = userInput[1];
|
|
24
24
|
```
|
|
25
25
|
|
|
26
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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-security",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Security rules for eslint",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/
|
|
21
|
+
"url": "git+https://github.com/eslint-community/eslint-plugin-security.git"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"eslint",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"author": "Node Security Project",
|
|
29
29
|
"license": "Apache-2.0",
|
|
30
30
|
"bugs": {
|
|
31
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/eslint-community/eslint-plugin-security/issues"
|
|
32
32
|
},
|
|
33
|
-
"homepage": "https://github.com/
|
|
33
|
+
"homepage": "https://github.com/eslint-community/eslint-plugin-security#readme",
|
|
34
34
|
"gitHooks": {
|
|
35
35
|
"pre-commit": "lint-staged"
|
|
36
36
|
},
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const { getImportAccessPath } = require('../utils/import-utils');
|
|
9
|
+
const childProcessPackageNames = ['child_process', 'node:child_process'];
|
|
10
|
+
|
|
8
11
|
//------------------------------------------------------------------------------
|
|
9
12
|
// Rule Definition
|
|
10
13
|
//------------------------------------------------------------------------------
|
|
@@ -20,54 +23,37 @@ module.exports = {
|
|
|
20
23
|
},
|
|
21
24
|
},
|
|
22
25
|
create: function (context) {
|
|
23
|
-
/*
|
|
24
|
-
* Stores variable identifiers pointing to child_process to check (child_process).exec()
|
|
25
|
-
*/
|
|
26
|
-
const childProcessIdentifiers = new Set();
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Extract identifiers assigned the expression `require("child_process")`.
|
|
30
|
-
* @param {Pattern} node
|
|
31
|
-
*/
|
|
32
|
-
function extractChildProcessIdentifiers(node) {
|
|
33
|
-
if (node.type !== 'Identifier') {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const variable = context.getScope().set.get(node.name);
|
|
37
|
-
if (!variable) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
for (const reference of variable.references) {
|
|
41
|
-
childProcessIdentifiers.add(reference.identifier);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
26
|
return {
|
|
46
27
|
CallExpression: function (node) {
|
|
47
28
|
if (node.callee.name === 'require') {
|
|
48
29
|
const args = node.arguments[0];
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
if (!pattern || pattern.type === 'Identifier') {
|
|
60
|
-
return context.report({ node: node, message: 'Found require("child_process")' });
|
|
61
|
-
}
|
|
30
|
+
if (
|
|
31
|
+
args &&
|
|
32
|
+
args.type === 'Literal' &&
|
|
33
|
+
childProcessPackageNames.includes(args.value) &&
|
|
34
|
+
node.parent.type !== 'VariableDeclarator' &&
|
|
35
|
+
node.parent.type !== 'AssignmentExpression' &&
|
|
36
|
+
node.parent.type !== 'MemberExpression'
|
|
37
|
+
) {
|
|
38
|
+
context.report({ node: node, message: 'Found require("' + args.value + '")' });
|
|
62
39
|
}
|
|
40
|
+
return;
|
|
63
41
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (node.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
42
|
+
|
|
43
|
+
// Reports non-literal `exec()` calls.
|
|
44
|
+
if (!node.arguments.length || node.arguments[0].type === 'Literal') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const pathInfo = getImportAccessPath({
|
|
48
|
+
node: node.callee,
|
|
49
|
+
scope: context.getScope(),
|
|
50
|
+
packageNames: childProcessPackageNames,
|
|
51
|
+
});
|
|
52
|
+
const fnName = pathInfo && pathInfo.path.length === 1 && pathInfo.path[0];
|
|
53
|
+
if (fnName !== 'exec') {
|
|
54
|
+
return;
|
|
70
55
|
}
|
|
56
|
+
context.report({ node: node, message: 'Found child_process.exec() with non Literal first argument' });
|
|
71
57
|
},
|
|
72
58
|
};
|
|
73
59
|
},
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const RuleTester = require('eslint').RuleTester;
|
|
4
|
-
const tester = new RuleTester(
|
|
4
|
+
const tester = new RuleTester({
|
|
5
|
+
parserOptions: {
|
|
6
|
+
ecmaVersion: 6,
|
|
7
|
+
sourceType: 'module',
|
|
8
|
+
},
|
|
9
|
+
});
|
|
5
10
|
|
|
6
11
|
const ruleName = 'detect-child-process';
|
|
7
12
|
const rule = require(`../rules/${ruleName}`);
|
|
@@ -9,53 +14,123 @@ const rule = require(`../rules/${ruleName}`);
|
|
|
9
14
|
tester.run(ruleName, rule, {
|
|
10
15
|
valid: [
|
|
11
16
|
"child_process.exec('ls')",
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
`
|
|
18
|
+
var {} = require('child_process');
|
|
19
|
+
var result = /hello/.exec(str);`,
|
|
20
|
+
`
|
|
21
|
+
var {} = require('node:child_process');
|
|
22
|
+
var result = /hello/.exec(str);`,
|
|
23
|
+
`
|
|
24
|
+
import {} from 'child_process';
|
|
25
|
+
var result = /hello/.exec(str);`,
|
|
26
|
+
`
|
|
27
|
+
import {} from 'node:child_process';
|
|
28
|
+
var result = /hello/.exec(str);`,
|
|
29
|
+
"var { spawn } = require('child_process'); spawn(str);",
|
|
30
|
+
"var { spawn } = require('node:child_process'); spawn(str);",
|
|
31
|
+
"import { spawn } from 'child_process'; spawn(str);",
|
|
32
|
+
"import { spawn } from 'node:child_process'; spawn(str);",
|
|
33
|
+
`
|
|
34
|
+
var foo = require('child_process');
|
|
35
|
+
function fn () {
|
|
36
|
+
var foo = /hello/;
|
|
37
|
+
var result = foo.exec(str);
|
|
38
|
+
}`,
|
|
39
|
+
"var child = require('child_process'); child.spawn(str)",
|
|
40
|
+
"var child = require('node:child_process'); child.spawn(str)",
|
|
41
|
+
"import child from 'child_process'; child.spawn(str)",
|
|
42
|
+
"import child from 'node:child_process'; child.spawn(str)",
|
|
43
|
+
`
|
|
44
|
+
var foo = require('child_process');
|
|
45
|
+
function fn () {
|
|
46
|
+
var result = foo.spawn(str);
|
|
47
|
+
}`,
|
|
48
|
+
"require('child_process').spawn(str)",
|
|
49
|
+
`
|
|
50
|
+
function fn () {
|
|
51
|
+
require('child_process').spawn(str)
|
|
52
|
+
}`,
|
|
22
53
|
],
|
|
23
54
|
invalid: [
|
|
24
55
|
{
|
|
25
56
|
code: "require('child_process')",
|
|
26
57
|
errors: [{ message: 'Found require("child_process")' }],
|
|
27
58
|
},
|
|
59
|
+
{
|
|
60
|
+
code: "require('node:child_process')",
|
|
61
|
+
errors: [{ message: 'Found require("node:child_process")' }],
|
|
62
|
+
},
|
|
28
63
|
{
|
|
29
64
|
code: "var child = require('child_process'); child.exec(com)",
|
|
30
|
-
errors: [{ message: 'Found
|
|
65
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument' }],
|
|
31
66
|
},
|
|
32
67
|
{
|
|
33
|
-
code: "var child = require('child_process'); child.exec()",
|
|
34
|
-
errors: [{ message: 'Found
|
|
68
|
+
code: "var child = require('node:child_process'); child.exec(com)",
|
|
69
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument' }],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
code: "import child from 'child_process'; child.exec(com)",
|
|
73
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument' }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
code: "import child from 'node:child_process'; child.exec(com)",
|
|
77
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument' }],
|
|
35
78
|
},
|
|
36
79
|
{
|
|
37
80
|
code: "var child = sinon.stub(require('child_process')); child.exec.returns({});",
|
|
38
81
|
errors: [{ message: 'Found require("child_process")' }],
|
|
39
82
|
},
|
|
83
|
+
{
|
|
84
|
+
code: "var child = sinon.stub(require('node:child_process')); child.exec.returns({});",
|
|
85
|
+
errors: [{ message: 'Found require("node:child_process")' }],
|
|
86
|
+
},
|
|
40
87
|
{
|
|
41
88
|
code: `
|
|
42
89
|
var foo = require('child_process');
|
|
43
90
|
function fn () {
|
|
44
91
|
var result = foo.exec(str);
|
|
45
92
|
}`,
|
|
46
|
-
errors: [
|
|
47
|
-
{ message: 'Found require("child_process")', line: 2 },
|
|
48
|
-
{ message: 'Found child_process.exec() with non Literal first argument', line: 4 },
|
|
49
|
-
],
|
|
93
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 4 }],
|
|
50
94
|
},
|
|
51
95
|
{
|
|
52
96
|
code: `
|
|
53
|
-
|
|
97
|
+
import foo from 'child_process';
|
|
98
|
+
function fn () {
|
|
99
|
+
var result = foo.exec(str);
|
|
100
|
+
}`,
|
|
101
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 4 }],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
code: `
|
|
105
|
+
import foo from 'node:child_process';
|
|
54
106
|
function fn () {
|
|
55
|
-
var foo = /hello/;
|
|
56
107
|
var result = foo.exec(str);
|
|
57
108
|
}`,
|
|
58
|
-
errors: [{ message: 'Found
|
|
109
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 4 }],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
code: `
|
|
113
|
+
require('child_process').exec(str)`,
|
|
114
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 2 }],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
code: `
|
|
118
|
+
function fn () {
|
|
119
|
+
require('child_process').exec(str)
|
|
120
|
+
}`,
|
|
121
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 3 }],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
code: `
|
|
125
|
+
const {exec} = require('child_process');
|
|
126
|
+
exec(str)`,
|
|
127
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 3 }],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
code: `
|
|
131
|
+
const {exec} = require('node:child_process');
|
|
132
|
+
exec(str)`,
|
|
133
|
+
errors: [{ message: 'Found child_process.exec() with non Literal first argument', line: 3 }],
|
|
59
134
|
},
|
|
60
135
|
],
|
|
61
136
|
});
|