Skip to content

Commit

Permalink
Prevent usage of dangerous JSX properties (no-danger)
Browse files Browse the repository at this point in the history
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>;
  • Loading branch information
scothis committed Jul 1, 2015
1 parent 824ba8d commit 0c132f5
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
27 changes: 27 additions & 0 deletions docs/rules/no-danger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 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

## Rule Details

The following patterns are considered warnings:

```js
var React = require('react');

var Hello = <div dangerouslySetInnerHTML={{ __html: "Hello World" }}></div>;
```

The following patterns are not considered warnings:

```js
var React = require('react');

var Hello = <div>Hello World</div>;
```

## When Not To Use It

If you are certain the content passed to dangerouslySetInnerHTML is sanitized HTML you can disable this rule.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = {
'display-name': require('./lib/rules/display-name'),
'wrap-multilines': require('./lib/rules/wrap-multilines'),
'self-closing-comp': require('./lib/rules/self-closing-comp'),
'no-danger': require('./lib/rules/no-danger'),
'no-did-mount-set-state': require('./lib/rules/no-did-mount-set-state'),
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state'),
'react-in-jsx-scope': require('./lib/rules/react-in-jsx-scope'),
Expand All @@ -28,6 +29,7 @@ module.exports = {
'display-name': 0,
'wrap-multilines': 0,
'self-closing-comp': 0,
'no-danger': 0,
'no-did-mount-set-state': 0,
'no-did-update-set-state': 0,
'react-in-jsx-scope': 0,
Expand Down
65 changes: 65 additions & 0 deletions lib/rules/no-danger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @fileoverview Prevent usage of dangerous JSX props
* @author Scott Andrews
*/
'use strict';

// ------------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------------

var DANGEROUS_MESSAGE = 'Dangerous property \'{{name}}\' found';

var DANGEROUS_PROPERTY_NAMES = [
'dangerouslySetInnerHTML'
];

var DANGEROUS_PROPERTIES = DANGEROUS_PROPERTY_NAMES.reduce(function (props, prop) {
props[prop] = prop;
return props;
}, Object.create(null));

// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------

/**
* Checks if a node name match the JSX tag convention.
* @param {String} name - Name of the node to check.
* @returns {boolean} Whether or not the node name match the JSX tag convention.
*/
var tagConvention = /^[a-z]|\-/;
function isTagName(name) {
return tagConvention.test(name);
}

/**
* Checks if a JSX attribute is dangerous.
* @param {String} name - Name of the attribute to check.
* @returns {boolean} Whether or not the attribute is dnagerous.
*/
function isDangerous(name) {
return name in DANGEROUS_PROPERTIES;
}

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = function(context) {

return {

JSXAttribute: function(node) {
if (isTagName(node.parent.name.name) && isDangerous(node.name.name)) {
context.report(node, DANGEROUS_MESSAGE, {
name: node.name.name
});
}
}

};

};

module.exports.schema = [];
32 changes: 32 additions & 0 deletions tests/lib/rules/no-danger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @fileoverview Tests for no-danger
* @author Scott Andrews
*/

'use strict';

// -----------------------------------------------------------------------------
// Requirements
// -----------------------------------------------------------------------------

var eslint = require('eslint').linter;
var ESLintTester = require('eslint-tester');

// -----------------------------------------------------------------------------
// Tests
// -----------------------------------------------------------------------------

var eslintTester = new ESLintTester(eslint);
eslintTester.addRuleTest('lib/rules/no-danger', {
valid: [
{code: '<App />;', ecmaFeatures: {jsx: true}},
{code: '<App dangerouslySetInnerHTML={{ __html: "" }} />;', ecmaFeatures: {jsx: true}},
{code: '<div className="bar"></div>;', ecmaFeatures: {jsx: true}}
],
invalid: [{
code: '<div dangerouslySetInnerHTML={{ __html: "" }}></div>;',
errors: [{message: 'Dangerous property \'dangerouslySetInnerHTML\' found'}],
ecmaFeatures: {jsx: true}
}
]
});

0 comments on commit 0c132f5

Please sign in to comment.