├── .dccache
├── .github
├── CODEOWNERS
└── snyk-code-screenshot.png
├── README.md
├── lib
├── index.js
├── rules
│ ├── no-dangerously-set-innerhtml.js
│ ├── no-find-dom-node.js
│ ├── no-javascript-urls.js
│ └── no-refs.js
└── util
│ └── docs.js
├── package.json
├── shared
└── messages.js
└── tests
└── lib
└── rules
├── no-dangerously-set-innerhtml.js
├── no-find-dom-node.js
├── no-javascript-urls.js
└── no-refs.js
/.dccache:
--------------------------------------------------------------------------------
1 | {"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/index.js":[186,1626076323433.372,"859be5749b2cbfaa7804e8043216b783e616c30b91ea235a4b1c232ebc8531c1"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/shared/messages.js":[254,1626076323434.7126,"9702be7c0ba72850fbff4a8b114e2f46229b98690f3f3556ffd012236be4af00"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/rules/no-dangerously-set-innerhtml.js":[1089,1626076323433.6375,"fe1f5332379625401fef4f20c7a1948ef38d2226435d9558939da719fe87637b"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/rules/no-find-dom-node.js":[1192,1626076323433.8083,"b06cf0c6ab65ac79440462252dd48bd0ff9343e49a8ffcf178fe3f3f5da60cc1"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/rules/no-javascript-urls.js":[1373,1626076323433.951,"7bb551a660b16163462043fd280f69b4347212459e9cc7b7ea34c9eb994a9ede"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/rules/no-refs.js":[983,1626076323434.0896,"08db4e24ab1f36e6353a33bd13b26131373a39b1ab79d97039667aacfae48814"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/lib/util/docs.js":[389,1626076323434.3228,"dcbda9ac9393c76b7ac11112f42f78a869a534a74f50144a6e1794d9a80fdaa1"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/tests/lib/rules/no-dangerously-set-innerhtml.js":[1071,1626076323435.1462,"830f95cbe700c2ee99f50c67e9bc0c2d7966297bacbeb0fa8888d9e113dbadd8"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/tests/lib/rules/no-find-dom-node.js":[1048,1626076323435.3857,"a3765bb9e928bb39143b0745eac82d172dcada875893f792f44ceaeb6acf6c30"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/tests/lib/rules/no-javascript-urls.js":[1019,1626076323435.535,"d7a096e2bf878048e9fdc2f59b9c325945c7c7d8faaccd1b1edf3ad6e235ef2b"],"/Users/lirantal/projects/repos/eslint-plugin-react-security/tests/lib/rules/no-refs.js":[972,1626076323435.6826,"ee4b45b02a87be16c12057a9d068e0017aa7bb94d97f5136e68416ff01d054ec"]}
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @snyk/devrel
2 |
--------------------------------------------------------------------------------
/.github/snyk-code-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/snyk-labs/eslint-plugin-react-security/e91c7b6a8deffef96ba27fbae4d9894936e6b2b8/.github/snyk-code-screenshot.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | A developer-friendly static code analysis for React security?
3 |
yes, it exists:
4 |
5 |
6 |
7 | Try Snyk Code, a developer-first SAST tool.
8 |
9 | Like an ESLint rule for react security, but better.
10 |
Did I mention it's free?
11 |
12 |
13 | ⚠️ Important notice, this repository *is not* publisher to npmjs, and it isn't the same as [eslint-plugin-react-security](https://www.npmjs.com/package/eslint-plugin-react-security), which is a different project, maintained by an entirely different developer.
14 |
15 | ⚠️ Maintenance notice: The `eslint-plugin-react-security` project is no longer under active maintenance by the Snyk team.
16 |
17 | Instead, we invite you to try out the Snyk Code IDE integrations for either [IntelliJ](https://support.snyk.io/hc/en-us/articles/360004032317-JetBrains-plugins) or [VSCode](https://support.snyk.io/hc/en-us/articles/360018585717-Visual-Studio-Code-extension-for-Snyk-Code-) which provide a developer-friendly secure coding experience while you code.
18 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Gathers all the ESLint rules and exports them on one object.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | module.exports.rules = require("requireindex")(`${__dirname}/rules`);
9 |
--------------------------------------------------------------------------------
/lib/rules/no-dangerously-set-innerhtml.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Rule to detect usage of dangerouslySetInnerHTML prop.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const docs = require("../util/docs");
13 |
14 | const message = require("../../shared/messages")[
15 | "no-dangerously-set-innerhtml"
16 | ];
17 |
18 | //------------------------------------------------------------------------------
19 | // Rule Definition
20 | //------------------------------------------------------------------------------
21 |
22 | module.exports = {
23 | meta: {
24 | type: "suggestion",
25 |
26 | docs: {
27 | description: "Detect usage of dangerouslySetInnerHTML prop.",
28 | category: "Security",
29 | recommended: true,
30 | url: docs("no-dangerously-set-innerhtml"),
31 | },
32 | },
33 | create: function (context) {
34 | return {
35 | JSXAttribute: function (node) {
36 | const prop = node.name.name;
37 |
38 | if (prop === "dangerouslySetInnerHTML") {
39 | context.report(node, message);
40 | }
41 | },
42 | };
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/lib/rules/no-find-dom-node.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Rule to detect usage of ReactDOM.findDOMNode().
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const docs = require("../util/docs");
13 |
14 | const message = require("../../shared/messages")["no-find-dom-node"];
15 |
16 | //------------------------------------------------------------------------------
17 | // Rule Definition
18 | //------------------------------------------------------------------------------
19 |
20 | module.exports = {
21 | meta: {
22 | type: "suggestion",
23 |
24 | docs: {
25 | description: "Detect usage of ReactDOM.findDOMNode().",
26 | category: "Security",
27 | recommended: true,
28 | url: docs("no-find-dom-node"),
29 | },
30 | },
31 | create: function (context) {
32 | return {
33 | CallExpression: function (node) {
34 | if (node.callee.name === "findDOMNode") {
35 | return context.report(node, message);
36 | }
37 |
38 | if (
39 | node.callee.property &&
40 | node.callee.property.name === "findDOMNode"
41 | ) {
42 | return context.report(node, message);
43 | }
44 | },
45 | };
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/lib/rules/no-javascript-urls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Rule to detect javascript: urls in JSX.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const docs = require("../util/docs");
13 |
14 | const message = require("../../shared/messages")["no-javascript-urls"];
15 |
16 | //------------------------------------------------------------------------------
17 | // Rule Definition
18 | //------------------------------------------------------------------------------
19 |
20 | function isJavaScriptURL(prop) {
21 | const url = new URL(prop);
22 |
23 | if (url.protocol !== "javascript:") return false;
24 |
25 | return true;
26 | }
27 |
28 | function isAnchor(name) {
29 | if (name === "a") return true;
30 | }
31 |
32 | function isHref(name) {
33 | if (name === "href") return true;
34 | }
35 |
36 | module.exports = {
37 | meta: {
38 | type: "suggestion",
39 |
40 | docs: {
41 | description: "Detect usage of javascript: urls in JSX.",
42 | category: "Security",
43 | recommended: true,
44 | url: docs("no-javascript-urls"),
45 | },
46 | },
47 | create: function (context) {
48 | return {
49 | JSXAttribute: function (node) {
50 | if (!isAnchor(node.parent.name.name)) return;
51 | if (!isHref(node.name.name)) return;
52 |
53 | if (isJavaScriptURL(node.value.value)) {
54 | return context.report(node, message);
55 | }
56 | },
57 | };
58 | },
59 | };
60 |
--------------------------------------------------------------------------------
/lib/rules/no-refs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Rule to detect usage of ref prop.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const docs = require("../util/docs");
13 |
14 | const message = require("../../shared/messages")["no-refs"];
15 |
16 | //------------------------------------------------------------------------------
17 | // Rule Definition
18 | //------------------------------------------------------------------------------
19 |
20 | module.exports = {
21 | meta: {
22 | type: "suggestion",
23 |
24 | docs: {
25 | description: "Detect usage of ref prop.",
26 | category: "Security",
27 | recommended: true,
28 | url: docs("no-refs"),
29 | },
30 | },
31 | create: function (context) {
32 | return {
33 | JSXAttribute: function (node) {
34 | const prop = node.name.name;
35 |
36 | if (prop === "ref") {
37 | context.report(node, message);
38 | }
39 | },
40 | };
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/lib/util/docs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Defines helper function for documentation URLs.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | /**
9 | * Returns documentation url for rule.
10 | * @params {String} rule - Rule name.
11 | * @returns {String} URL for rule documentation.
12 | */
13 | function docs(rule) {
14 | return `https://github.com/snyk-labs/eslint-plugin-react-security/tree/master/docs/rules/${rule}.md`;
15 | }
16 |
17 | module.exports = docs;
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-plugin-react-security",
3 | "version": "0.0.0",
4 | "description": "For finding security issues in React projects.",
5 | "keywords": [
6 | "eslint",
7 | "eslintplugin",
8 | "eslint-plugin"
9 | ],
10 | "author": "Ron Perris ",
11 | "main": "lib/index.js",
12 | "scripts": {
13 | "test": "mocha tests --recursive"
14 | },
15 | "dependencies": {
16 | "requireindex": "~1.1.0"
17 | },
18 | "devDependencies": {
19 | "eslint": "^7.1.0",
20 | "mocha": "^7.2.0"
21 | },
22 | "engines": {
23 | "node": ">=12.0.0"
24 | },
25 | "license": "ISC"
26 | }
27 |
--------------------------------------------------------------------------------
/shared/messages.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "no-dangerously-set-innerhtml": "dangrouslySetInnerHTML prop usage detected",
3 | "no-javascript-urls": "javascript: url in JSX detected",
4 | "no-find-dom-node": "findDOMNode usage detected",
5 | "no-refs": "refs prop usage detected",
6 | };
7 |
--------------------------------------------------------------------------------
/tests/lib/rules/no-dangerously-set-innerhtml.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for no-dangerously-set-innerhtml rule.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const rule = require("../../../lib/rules/no-dangerously-set-innerhtml");
13 | const { RuleTester } = require("eslint");
14 | const message = require("../../../shared/messages")[
15 | "no-dangerously-set-innerhtml"
16 | ];
17 |
18 | const parserOptions = {
19 | ecmaVersion: 2018,
20 | sourceType: "module",
21 | ecmaFeatures: {
22 | jsx: true,
23 | },
24 | };
25 |
26 | // -----------------------------------------------------------------------------
27 | // Tests
28 | // -----------------------------------------------------------------------------
29 |
30 | const ruleTester = new RuleTester({ parserOptions });
31 |
32 | ruleTester.run("no-dangerously-set-innerhtml", rule, {
33 | valid: [{ code: ';' }],
34 | invalid: [
35 | {
36 | code: ';',
37 | errors: [{ message }],
38 | },
39 | ],
40 | });
41 |
--------------------------------------------------------------------------------
/tests/lib/rules/no-find-dom-node.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for ReactDOM.findDOMNode() usage rule.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const rule = require("../../../lib/rules/no-find-dom-node");
13 | const { RuleTester } = require("eslint");
14 | const message = require("../../../shared/messages")["no-find-dom-node"];
15 |
16 | const parserOptions = {
17 | ecmaVersion: 2018,
18 | sourceType: "module",
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | };
23 |
24 | // -----------------------------------------------------------------------------
25 | // Tests
26 | // -----------------------------------------------------------------------------
27 |
28 | const ruleTester = new RuleTester({ parserOptions });
29 |
30 | ruleTester.run("no-find-dom-node", rule, {
31 | valid: [{ code: "foo()" }],
32 | invalid: [
33 | {
34 | code: "findDOMNode()",
35 | errors: [{ message }],
36 | },
37 | {
38 | code: "ReactDOM.findDOMNode()",
39 | errors: [{ message }],
40 | },
41 | ],
42 | });
43 |
--------------------------------------------------------------------------------
/tests/lib/rules/no-javascript-urls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for javascript: urls in JSX rule.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const rule = require("../../../lib/rules/no-javascript-urls");
13 | const { RuleTester } = require("eslint");
14 | const message = require("../../../shared/messages")["no-javascript-urls"];
15 |
16 | const parserOptions = {
17 | ecmaVersion: 2018,
18 | sourceType: "module",
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | };
23 |
24 | // -----------------------------------------------------------------------------
25 | // Tests
26 | // -----------------------------------------------------------------------------
27 |
28 | const ruleTester = new RuleTester({ parserOptions });
29 |
30 | ruleTester.run("no-javascript-urls", rule, {
31 | valid: [{ code: '' }],
32 | invalid: [
33 | {
34 | code: '',
35 | errors: [{ message }],
36 | },
37 | ],
38 | });
39 |
--------------------------------------------------------------------------------
/tests/lib/rules/no-refs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for JSX ref prop usage rule.
3 | * @author Ron Perris
4 | */
5 |
6 | "use strict";
7 |
8 | // -----------------------------------------------------------------------------
9 | // Requirements
10 | // -----------------------------------------------------------------------------
11 |
12 | const rule = require("../../../lib/rules/no-refs");
13 | const { RuleTester } = require("eslint");
14 | const message = require("../../../shared/messages")["no-refs"];
15 |
16 | const parserOptions = {
17 | ecmaVersion: 2018,
18 | sourceType: "module",
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | };
23 |
24 | // -----------------------------------------------------------------------------
25 | // Tests
26 | // -----------------------------------------------------------------------------
27 |
28 | const ruleTester = new RuleTester({ parserOptions });
29 |
30 | ruleTester.run("no-refs", rule, {
31 | valid: [{ code: ';' }],
32 | invalid: [
33 | {
34 | code: ";",
35 | errors: [{ message }],
36 | },
37 | ],
38 | });
39 |
--------------------------------------------------------------------------------