eslint-plugin-security 2.0.0 → 2.1.1

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.
Files changed (23) hide show
  1. package/.eslint-doc-generatorrc.js +1 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +28 -16
  4. package/docs/rules/detect-new-buffer.md +4 -0
  5. package/docs/rules/detect-object-injection.md +31 -0
  6. package/index.js +9 -1
  7. package/package.json +1 -1
  8. package/rules/detect-eval-with-expression.js +3 -3
  9. package/test/configs/index.js +16 -0
  10. package/test/{detect-bidi-characters.js → rules/detect-bidi-characters.js} +2 -2
  11. package/test/{detect-buffer-noassert.js → rules/detect-buffer-noassert.js} +1 -1
  12. package/test/{detect-child-process.js → rules/detect-child-process.js} +1 -1
  13. package/test/{detect-disable-mustache-escape.js → rules/detect-disable-mustache-escape.js} +1 -1
  14. package/test/{detect-eval-with-expression.js → rules/detect-eval-with-expression.js} +2 -2
  15. package/test/{detect-new-buffer.js → rules/detect-new-buffer.js} +1 -1
  16. package/test/{detect-no-csrf-before-method-override.js → rules/detect-no-csrf-before-method-override.js} +1 -1
  17. package/test/{detect-non-literal-fs-filename.js → rules/detect-non-literal-fs-filename.js} +2 -2
  18. package/test/{detect-non-literal-regexp.js → rules/detect-non-literal-regexp.js} +1 -1
  19. package/test/{detect-non-literal-require.js → rules/detect-non-literal-require.js} +1 -1
  20. package/test/{detect-object-injection.js → rules/detect-object-injection.js} +1 -1
  21. package/test/{detect-possible-timing-attacks.js → rules/detect-possible-timing-attacks.js} +1 -1
  22. package/test/{detect-pseudoRandomBytes.js → rules/detect-pseudoRandomBytes.js} +1 -1
  23. package/test/{detect-unsafe-regexp.js → rules/detect-unsafe-regexp.js} +1 -1
@@ -3,6 +3,7 @@ const prettierRC = require('./.prettierrc.json');
3
3
 
4
4
  /** @type {import('eslint-doc-generator').GenerateOptions} */
5
5
  const config = {
6
+ ignoreConfig: ['recommended-legacy'],
6
7
  postprocess: (doc) => format(doc, { ...prettierRC, parser: 'markdown' }),
7
8
  };
8
9
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ### [2.1.1](https://www.github.com/eslint-community/eslint-plugin-security/compare/v2.1.0...v2.1.1) (2024-02-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * Ensure empty eval() doesn't crash detect-eval-with-expression ([#139](https://www.github.com/eslint-community/eslint-plugin-security/issues/139)) ([8a7c7db](https://www.github.com/eslint-community/eslint-plugin-security/commit/8a7c7db1e2b49e2831d510b8dc1db235dee0edf0))
9
+
10
+ ## [2.1.0](https://www.github.com/eslint-community/eslint-plugin-security/compare/v2.0.0...v2.1.0) (2023-12-15)
11
+
12
+
13
+ ### Features
14
+
15
+ * add config recommended-legacy ([#132](https://www.github.com/eslint-community/eslint-plugin-security/issues/132)) ([13d3f2f](https://www.github.com/eslint-community/eslint-plugin-security/commit/13d3f2fc6ba327c894959db30462f3fda0272f0c))
16
+
3
17
  ## [2.0.0](https://www.github.com/eslint-community/eslint-plugin-security/compare/v1.7.1...v2.0.0) (2023-10-17)
4
18
 
5
19
 
package/README.md CHANGED
@@ -20,6 +20,8 @@ yarn add --dev eslint-plugin-security
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### Flat config (requires eslint >= v8.23.0)
24
+
23
25
  Add the following to your `eslint.config.js` file:
24
26
 
25
27
  ```js
@@ -28,6 +30,16 @@ const pluginSecurity = require('eslint-plugin-security');
28
30
  module.exports = [pluginSecurity.configs.recommended];
29
31
  ```
30
32
 
33
+ ### eslintrc config (deprecated)
34
+
35
+ Add the following to your `.eslintrc` file:
36
+
37
+ ```js
38
+ module.exports = {
39
+ extends: ['plugin:security/recommended-legacy'],
40
+ };
41
+ ```
42
+
31
43
  ## Developer guide
32
44
 
33
45
  - Use [GitHub pull requests](https://help.github.com/articles/using-pull-requests).
@@ -52,21 +64,21 @@ npm test
52
64
  ⚠️ Configurations set to warn in.\
53
65
  ✅ Set in the `recommended` configuration.
54
66
 
55
- | Name                                  | Description | ⚠️ |
56
- | :------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | :-- |
57
- | [detect-bidi-characters](docs/rules/detect-bidi-characters.md) | Detects trojan source attacks that employ unicode bidi attacks to inject malicious code. | ✅ |
58
- | [detect-buffer-noassert](docs/rules/detect-buffer-noassert.md) | Detects calls to "buffer" with "noAssert" flag set. | ✅ |
59
- | [detect-child-process](docs/rules/detect-child-process.md) | Detects instances of "child_process" & non-literal "exec()" calls. | ✅ |
60
- | [detect-disable-mustache-escape](docs/rules/detect-disable-mustache-escape.md) | Detects "object.escapeMarkup = false", which can be used with some template engines to disable escaping of HTML entities. | ✅ |
61
- | [detect-eval-with-expression](docs/rules/detect-eval-with-expression.md) | Detects "eval(variable)" which can allow an attacker to run arbitrary code inside your process. | ✅ |
62
- | [detect-new-buffer](docs/rules/detect-new-buffer.md) | Detects instances of new Buffer(argument) where argument is any non-literal value. | ✅ |
63
- | [detect-no-csrf-before-method-override](docs/rules/detect-no-csrf-before-method-override.md) | Detects Express "csrf" middleware setup before "method-override" middleware. | ✅ |
64
- | [detect-non-literal-fs-filename](docs/rules/detect-non-literal-fs-filename.md) | Detects variable in filename argument of "fs" calls, which might allow an attacker to access anything on your system. | ✅ |
65
- | [detect-non-literal-regexp](docs/rules/detect-non-literal-regexp.md) | Detects "RegExp(variable)", which might allow an attacker to DOS your server with a long-running regular expression. | ✅ |
66
- | [detect-non-literal-require](docs/rules/detect-non-literal-require.md) | Detects "require(variable)", which might allow an attacker to load and run arbitrary code, or access arbitrary files on disk. | ✅ |
67
- | [detect-object-injection](docs/rules/detect-object-injection.md) | Detects "variable[key]" as a left- or right-hand assignment operand. | ✅ |
68
- | [detect-possible-timing-attacks](docs/rules/detect-possible-timing-attacks.md) | Detects insecure comparisons (`==`, `!=`, `!==` and `===`), which check input sequentially. | ✅ |
69
- | [detect-pseudoRandomBytes](docs/rules/detect-pseudoRandomBytes.md) | Detects if "pseudoRandomBytes()" is in use, which might not give you the randomness you need and expect. | ✅ |
70
- | [detect-unsafe-regex](docs/rules/detect-unsafe-regex.md) | Detects potentially unsafe regular expressions, which may take a very long time to run, blocking the event loop. | ✅ |
67
+ | Name                                  | Description | ⚠️ |
68
+ | :------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-- |
69
+ | [detect-bidi-characters](docs/rules/detect-bidi-characters.md) | Detects trojan source attacks that employ unicode bidi attacks to inject malicious code. | ✅ |
70
+ | [detect-buffer-noassert](docs/rules/detect-buffer-noassert.md) | Detects calls to "buffer" with "noAssert" flag set. | ✅ |
71
+ | [detect-child-process](docs/rules/detect-child-process.md) | Detects instances of "child_process" & non-literal "exec()" calls. | ✅ |
72
+ | [detect-disable-mustache-escape](docs/rules/detect-disable-mustache-escape.md) | Detects "object.escapeMarkup = false", which can be used with some template engines to disable escaping of HTML entities. | ✅ |
73
+ | [detect-eval-with-expression](docs/rules/detect-eval-with-expression.md) | Detects "eval(variable)" which can allow an attacker to run arbitrary code inside your process. | ✅ |
74
+ | [detect-new-buffer](docs/rules/detect-new-buffer.md) | Detects instances of new Buffer(argument) where argument is any non-literal value. ([new Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)) | ✅ |
75
+ | [detect-no-csrf-before-method-override](docs/rules/detect-no-csrf-before-method-override.md) | Detects Express "csrf" middleware setup before "method-override" middleware. | ✅ |
76
+ | [detect-non-literal-fs-filename](docs/rules/detect-non-literal-fs-filename.md) | Detects variable in filename argument of "fs" calls, which might allow an attacker to access anything on your system. | ✅ |
77
+ | [detect-non-literal-regexp](docs/rules/detect-non-literal-regexp.md) | Detects "RegExp(variable)", which might allow an attacker to DOS your server with a long-running regular expression. | ✅ |
78
+ | [detect-non-literal-require](docs/rules/detect-non-literal-require.md) | Detects "require(variable)", which might allow an attacker to load and run arbitrary code, or access arbitrary files on disk. | ✅ |
79
+ | [detect-object-injection](docs/rules/detect-object-injection.md) | Detects "variable[key]" as a left- or right-hand assignment operand. | ✅ |
80
+ | [detect-possible-timing-attacks](docs/rules/detect-possible-timing-attacks.md) | Detects insecure comparisons (`==`, `!=`, `!==` and `===`), which check input sequentially. | ✅ |
81
+ | [detect-pseudoRandomBytes](docs/rules/detect-pseudoRandomBytes.md) | Detects if "pseudoRandomBytes()" is in use, which might not give you the randomness you need and expect. | ✅ |
82
+ | [detect-unsafe-regex](docs/rules/detect-unsafe-regex.md) | Detects potentially unsafe regular expressions, which may take a very long time to run, blocking the event loop. | ✅ |
71
83
 
72
84
  <!-- end auto-generated rules list -->
@@ -3,3 +3,7 @@
3
3
  ⚠️ This rule _warns_ in the ✅ `recommended` config.
4
4
 
5
5
  <!-- end auto-generated rule header -->
6
+
7
+ `new Buffer()` now emits a deprecation warning in Node.js.
8
+
9
+ More information: [new Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
@@ -4,4 +4,35 @@
4
4
 
5
5
  <!-- end auto-generated rule header -->
6
6
 
7
+ JavaScript allows you to use expressions to access object properties in addition to using dot notation. So instead of writing this:
8
+
9
+ ```js
10
+ object.name = 'foo';
11
+ ```
12
+
13
+ You can write this:
14
+
15
+ ```js
16
+ object['name'] = 'foo';
17
+ ```
18
+
19
+ Square bracket notation allows any expression to be used in place of an identifier, so you can also do this:
20
+
21
+ ```js
22
+ const key = 'name';
23
+ object[key] = 'foo';
24
+ ```
25
+
26
+ By doing so, you've now obfuscated the property name from the reader, which makes it easy for a malicious actor to replace the value of `key` and change the behavior of the code.
27
+
28
+ This rule flags any expression in the form of `object[expression]` no matter where it occurs. Examples of patterns this will be flagged are:
29
+
30
+ ```js
31
+ object[key] = value;
32
+
33
+ value = object[key];
34
+
35
+ doSomething(object[key]);
36
+ ```
37
+
7
38
  More information: [The Dangers of Square Bracket Notation](../the-dangers-of-square-bracket-notation.md)
package/index.js CHANGED
@@ -66,6 +66,14 @@ const recommended = {
66
66
  },
67
67
  };
68
68
 
69
- Object.assign(plugin.configs, { recommended });
69
+ const recommendedLegacy = {
70
+ plugins: ['security'],
71
+ rules: recommended.rules,
72
+ };
73
+
74
+ Object.assign(plugin.configs, {
75
+ recommended,
76
+ 'recommended-legacy': recommendedLegacy
77
+ });
70
78
 
71
79
  module.exports = plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-security",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Security rules for eslint",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -19,10 +19,10 @@ module.exports = {
19
19
  url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-eval-with-expression.md',
20
20
  },
21
21
  },
22
- create: function (context) {
22
+ create(context) {
23
23
  return {
24
- CallExpression: function (node) {
25
- if (node.callee.name === 'eval' && node.arguments[0].type !== 'Literal') {
24
+ CallExpression(node) {
25
+ if (node.callee.name === 'eval' && node.arguments.length && node.arguments[0].type !== 'Literal') {
26
26
  context.report({ node: node, message: `eval with argument of type ${node.arguments[0].type}` });
27
27
  }
28
28
  },
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+ const plugin = require('../../index.js');
3
+ const assert = require('assert').strict;
4
+
5
+ describe('export plugin object', () => {
6
+ it('should export rules', () => {
7
+ assert(plugin.rules);
8
+ assert(typeof plugin.rules['detect-unsafe-regex'] === 'object');
9
+ });
10
+
11
+ it('should export configs', () => {
12
+ assert(plugin.configs);
13
+ assert(plugin.configs['recommended']);
14
+ assert(plugin.configs['recommended-legacy']);
15
+ });
16
+ });
@@ -4,7 +4,7 @@ const RuleTester = require('eslint').RuleTester;
4
4
  const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-bidi-characters';
7
- const Rule = require(`../rules/${ruleName}`);
7
+ const Rule = require(`../../rules/${ruleName}`);
8
8
 
9
9
  tester.run(ruleName, Rule, {
10
10
  valid: [
@@ -54,7 +54,7 @@ tester.run(`${ruleName} in comment-line`, Rule, {
54
54
  console.log("You are an admin.");
55
55
  /* end admins only ‮
56
56
  ⁦*/
57
- /* end admins only ‮
57
+ /* end admins only ‮
58
58
  { ⁦*/
59
59
  `,
60
60
  errors: [
@@ -4,7 +4,7 @@ const RuleTester = require('eslint').RuleTester;
4
4
  const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-buffer-noassert';
7
- const rule = require(`../rules/${ruleName}`);
7
+ const rule = require(`../../rules/${ruleName}`);
8
8
 
9
9
  const allMethodNames = [...rule.meta.__methodsToCheck.read, ...rule.meta.__methodsToCheck.write];
10
10
 
@@ -9,7 +9,7 @@ const tester = new RuleTester({
9
9
  });
10
10
 
11
11
  const ruleName = 'detect-child-process';
12
- const rule = require(`../rules/${ruleName}`);
12
+ const rule = require(`../../rules/${ruleName}`);
13
13
 
14
14
  tester.run(ruleName, rule, {
15
15
  valid: [
@@ -5,7 +5,7 @@ const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-disable-mustache-escape';
7
7
 
8
- tester.run(ruleName, require(`../rules/${ruleName}`), {
8
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
9
9
  valid: [{ code: 'escapeMarkup = false' }],
10
10
  invalid: [
11
11
  {
@@ -5,8 +5,8 @@ const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-eval-with-expression';
7
7
 
8
- tester.run(ruleName, require(`../rules/${ruleName}`), {
9
- valid: [{ code: "eval('alert()')" }],
8
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
9
+ valid: [{ code: "eval('alert()')" }, { code: 'eval("some nefarious code");' }, { code: 'eval()' }],
10
10
  invalid: [
11
11
  {
12
12
  code: 'eval(a);',
@@ -6,7 +6,7 @@ const tester = new RuleTester();
6
6
  const ruleName = 'detect-new-buffer';
7
7
  const invalid = 'var a = new Buffer(c)';
8
8
 
9
- tester.run(ruleName, require(`../rules/${ruleName}`), {
9
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
10
10
  valid: [{ code: "var a = new Buffer('test')" }],
11
11
  invalid: [
12
12
  {
@@ -5,7 +5,7 @@ const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-no-csrf-before-method-override';
7
7
 
8
- tester.run(ruleName, require(`../rules/${ruleName}`), {
8
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
9
9
  valid: [{ code: 'express.methodOverride();express.csrf()' }],
10
10
  invalid: [
11
11
  {
@@ -10,7 +10,7 @@ const tester = new RuleTester({
10
10
 
11
11
  const ruleName = 'detect-non-literal-fs-filename';
12
12
 
13
- tester.run(ruleName, require(`../rules/${ruleName}`), {
13
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
14
14
  valid: [
15
15
  {
16
16
  code: `var fs = require('fs');
@@ -29,7 +29,7 @@ tester.run(ruleName, require(`../rules/${ruleName}`), {
29
29
  import { promises as fsp } from 'fs';
30
30
  import fs from 'fs';
31
31
  import path from 'path';
32
-
32
+
33
33
  const index = await fsp.readFile(path.resolve(__dirname, './index.html'), 'utf-8');
34
34
  const key = fs.readFileSync(path.join(__dirname, './ssl.key'));
35
35
  await fsp.writeFile(path.resolve(__dirname, './sitemap.xml'), sitemap);`,
@@ -6,7 +6,7 @@ const tester = new RuleTester();
6
6
  const ruleName = 'detect-non-literal-regexp';
7
7
  const invalid = "var a = new RegExp(c, 'i')";
8
8
 
9
- tester.run(ruleName, require(`../rules/${ruleName}`), {
9
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
10
10
  valid: [
11
11
  { code: "var a = new RegExp('ab+c', 'i')" },
12
12
  {
@@ -6,7 +6,7 @@ const tester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
6
6
 
7
7
  const ruleName = 'detect-non-literal-require';
8
8
 
9
- tester.run(ruleName, require(`../rules/${ruleName}`), {
9
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
10
10
  valid: [
11
11
  { code: "var a = require('b')" },
12
12
  { code: 'var a = require(`b`)' },
@@ -5,7 +5,7 @@ const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-object-injection';
7
7
 
8
- const Rule = require(`../rules/${ruleName}`);
8
+ const Rule = require(`../../rules/${ruleName}`);
9
9
 
10
10
  const valid = 'var a = {};';
11
11
  // const invalidVariable = "TODO";
@@ -4,7 +4,7 @@ const RuleTester = require('eslint').RuleTester;
4
4
  const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-possible-timing-attacks';
7
- const Rule = require(`../rules/${ruleName}`);
7
+ const Rule = require(`../../rules/${ruleName}`);
8
8
 
9
9
  const valid = 'if (age === 5) {}';
10
10
  const invalidLeft = "if (password === 'mypass') {}";
@@ -6,7 +6,7 @@ const tester = new RuleTester();
6
6
  const ruleName = 'detect-pseudoRandomBytes';
7
7
  const invalid = 'crypto.pseudoRandomBytes';
8
8
 
9
- tester.run(ruleName, require(`../rules/${ruleName}`), {
9
+ tester.run(ruleName, require(`../../rules/${ruleName}`), {
10
10
  valid: [{ code: 'crypto.randomBytes' }],
11
11
  invalid: [
12
12
  {
@@ -4,7 +4,7 @@ const RuleTester = require('eslint').RuleTester;
4
4
  const tester = new RuleTester();
5
5
 
6
6
  const ruleName = 'detect-unsafe-regex';
7
- const Rule = require(`../rules/${ruleName}`);
7
+ const Rule = require(`../../rules/${ruleName}`);
8
8
 
9
9
  tester.run(ruleName, Rule, {
10
10
  valid: [{ code: '/^d+1337d+$/' }],