Skip to content

Commit 0c132f5

Browse files
committed
Prevent usage of dangerous JSX properties (no-danger)
Dangerous properties in React are those whose behavior is known to be a common source of application vulnerabilities. The properties names clearly indicate they are dangerous and should be avoided unless great care is taken. See https://facebook.github.io/react/tips/dangerously-set-inner-html.html The following patterns are considered warnings: var Hello = <div dangerouslySetInnerHTML={{ __html: "Hello World" }}></div>; The following patterns are not considered warnings: var Hello = <div>Hello World</div>;
1 parent 824ba8d commit 0c132f5

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed

docs/rules/no-danger.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Prevent usage of dangerous JSX properties (no-danger)
2+
3+
Dangerous properties in React are those whose behavior is known to be a common source of application vulnerabilities. The properties names clearly indicate they are dangerous and should be avoided unless great care is taken.
4+
5+
See https://facebook.github.io/react/tips/dangerously-set-inner-html.html
6+
7+
## Rule Details
8+
9+
The following patterns are considered warnings:
10+
11+
```js
12+
var React = require('react');
13+
14+
var Hello = <div dangerouslySetInnerHTML={{ __html: "Hello World" }}></div>;
15+
```
16+
17+
The following patterns are not considered warnings:
18+
19+
```js
20+
var React = require('react');
21+
22+
var Hello = <div>Hello World</div>;
23+
```
24+
25+
## When Not To Use It
26+
27+
If you are certain the content passed to dangerouslySetInnerHTML is sanitized HTML you can disable this rule.

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
'display-name': require('./lib/rules/display-name'),
99
'wrap-multilines': require('./lib/rules/wrap-multilines'),
1010
'self-closing-comp': require('./lib/rules/self-closing-comp'),
11+
'no-danger': require('./lib/rules/no-danger'),
1112
'no-did-mount-set-state': require('./lib/rules/no-did-mount-set-state'),
1213
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state'),
1314
'react-in-jsx-scope': require('./lib/rules/react-in-jsx-scope'),
@@ -28,6 +29,7 @@ module.exports = {
2829
'display-name': 0,
2930
'wrap-multilines': 0,
3031
'self-closing-comp': 0,
32+
'no-danger': 0,
3133
'no-did-mount-set-state': 0,
3234
'no-did-update-set-state': 0,
3335
'react-in-jsx-scope': 0,

lib/rules/no-danger.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @fileoverview Prevent usage of dangerous JSX props
3+
* @author Scott Andrews
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Constants
9+
// ------------------------------------------------------------------------------
10+
11+
var DANGEROUS_MESSAGE = 'Dangerous property \'{{name}}\' found';
12+
13+
var DANGEROUS_PROPERTY_NAMES = [
14+
'dangerouslySetInnerHTML'
15+
];
16+
17+
var DANGEROUS_PROPERTIES = DANGEROUS_PROPERTY_NAMES.reduce(function (props, prop) {
18+
props[prop] = prop;
19+
return props;
20+
}, Object.create(null));
21+
22+
// ------------------------------------------------------------------------------
23+
// Helpers
24+
// ------------------------------------------------------------------------------
25+
26+
/**
27+
* Checks if a node name match the JSX tag convention.
28+
* @param {String} name - Name of the node to check.
29+
* @returns {boolean} Whether or not the node name match the JSX tag convention.
30+
*/
31+
var tagConvention = /^[a-z]|\-/;
32+
function isTagName(name) {
33+
return tagConvention.test(name);
34+
}
35+
36+
/**
37+
* Checks if a JSX attribute is dangerous.
38+
* @param {String} name - Name of the attribute to check.
39+
* @returns {boolean} Whether or not the attribute is dnagerous.
40+
*/
41+
function isDangerous(name) {
42+
return name in DANGEROUS_PROPERTIES;
43+
}
44+
45+
// ------------------------------------------------------------------------------
46+
// Rule Definition
47+
// ------------------------------------------------------------------------------
48+
49+
module.exports = function(context) {
50+
51+
return {
52+
53+
JSXAttribute: function(node) {
54+
if (isTagName(node.parent.name.name) && isDangerous(node.name.name)) {
55+
context.report(node, DANGEROUS_MESSAGE, {
56+
name: node.name.name
57+
});
58+
}
59+
}
60+
61+
};
62+
63+
};
64+
65+
module.exports.schema = [];

tests/lib/rules/no-danger.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @fileoverview Tests for no-danger
3+
* @author Scott Andrews
4+
*/
5+
6+
'use strict';
7+
8+
// -----------------------------------------------------------------------------
9+
// Requirements
10+
// -----------------------------------------------------------------------------
11+
12+
var eslint = require('eslint').linter;
13+
var ESLintTester = require('eslint-tester');
14+
15+
// -----------------------------------------------------------------------------
16+
// Tests
17+
// -----------------------------------------------------------------------------
18+
19+
var eslintTester = new ESLintTester(eslint);
20+
eslintTester.addRuleTest('lib/rules/no-danger', {
21+
valid: [
22+
{code: '<App />;', ecmaFeatures: {jsx: true}},
23+
{code: '<App dangerouslySetInnerHTML={{ __html: "" }} />;', ecmaFeatures: {jsx: true}},
24+
{code: '<div className="bar"></div>;', ecmaFeatures: {jsx: true}}
25+
],
26+
invalid: [{
27+
code: '<div dangerouslySetInnerHTML={{ __html: "" }}></div>;',
28+
errors: [{message: 'Dangerous property \'dangerouslySetInnerHTML\' found'}],
29+
ecmaFeatures: {jsx: true}
30+
}
31+
]
32+
});

0 commit comments

Comments
 (0)