Skip to content

Commit b9d2eb5

Browse files
seancraterljharb
authored andcommitted
[Fix] jsx-no-target-blank: allow no-referrer without noopener by default
Fixes #2022.
1 parent 3385caa commit b9d2eb5

File tree

4 files changed

+26
-11
lines changed

4 files changed

+26
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ Enable the rules that you would like to use.
176176
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Enforce no duplicate props
177177
* [react/jsx-no-literals](docs/rules/jsx-no-literals.md): Prevent using string literals in React component definition
178178
* [react/jsx-no-script-url](docs/rules/jsx-no-script-url.md): Forbid `javascript:` URLs
179-
* [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md): Forbid target="_blank" attribute without rel="noopener noreferrer"
179+
* [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md): Forbid `target="_blank"` attribute without `rel="noreferrer"`
180180
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
181181
* [react/jsx-no-useless-fragment](docs/rules/jsx-no-useless-fragment.md): Disallow unnecessary fragments (fixable)
182182
* [react/jsx-one-expression-per-line](docs/rules/jsx-one-expression-per-line.md): Limit to one expression per line in JSX (fixable)

docs/rules/jsx-no-target-blank.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
When creating a JSX element that has an `a` tag, it is often desired to have
44
the link open in a new tab using the `target='_blank'` attribute. Using this
5-
attribute unaccompanied by `rel='noreferrer noopener'`, however, is a severe
6-
security vulnerability ([see here for more details](https://mathiasbynens.github.io/rel-noopener))
7-
This rules requires that you accompany `target='_blank'` attributes with `rel='noreferrer noopener'`.
5+
attribute unaccompanied by `rel='noreferrer'`, however, is a severe
6+
security vulnerability ([see here for more details](https://html.spec.whatwg.org/multipage/links.html#link-type-noopener))
7+
This rules requires that you accompany `target='_blank'` attributes with `rel='noreferrer'`.
88

99
## Rule Details
1010

1111
This rule aims to prevent user generated links from creating security vulnerabilities by requiring
12-
`rel='noreferrer noopener'` for external links, and optionally any dynamically generated links.
12+
`rel='noreferrer'` for external links, and optionally any dynamically generated links.
1313

1414
## Rule Options
1515
```json
@@ -39,6 +39,7 @@ The following patterns are **not** considered errors:
3939

4040
```jsx
4141
var Hello = <p target="_blank"></p>
42+
var Hello = <a target="_blank" rel="noreferrer" href="http://example.com"></a>
4243
var Hello = <a target="_blank" rel="noopener noreferrer" href="http://example.com"></a>
4344
var Hello = <a target="_blank" href="relative/path/in/the/host"></a>
4445
var Hello = <a target="_blank" href="/absolute/path/in/the/host"></a>

lib/rules/jsx-no-target-blank.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function hasSecureRel(element, allowReferrer) {
5353
attr.value.expression.value
5454
));
5555
const tags = value && value.toLowerCase && value.toLowerCase().split(' ');
56-
return tags && tags.indexOf('noopener') >= 0 && (allowReferrer || tags.indexOf('noreferrer') >= 0);
56+
return tags && (allowReferrer ? tags.indexOf('noopener') >= 0 : tags.indexOf('noreferrer') >= 0);
5757
}
5858
return false;
5959
});
@@ -62,7 +62,7 @@ function hasSecureRel(element, allowReferrer) {
6262
module.exports = {
6363
meta: {
6464
docs: {
65-
description: 'Forbid target="_blank" attribute without rel="noopener noreferrer"',
65+
description: 'Forbid `target="_blank"` attribute without `rel="noreferrer"`',
6666
category: 'Best Practices',
6767
recommended: true,
6868
url: docsUrl('jsx-no-target-blank')
@@ -102,8 +102,8 @@ module.exports = {
102102
if (hasExternalLink(node.parent, linkAttribute) || (enforceDynamicLinks === 'always' && hasDynamicLink(node.parent, linkAttribute))) {
103103
context.report({
104104
node,
105-
message: 'Using target="_blank" without rel="noopener noreferrer" ' +
106-
'is a security risk: see https://mathiasbynens.github.io/rel-noopener'
105+
message: 'Using target="_blank" without rel="noreferrer" ' +
106+
'is a security risk: see https://html.spec.whatwg.org/multipage/links.html#link-type-noopener'
107107
});
108108
}
109109
}

tests/lib/rules/jsx-no-target-blank.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ const parserOptions = {
2626

2727
const ruleTester = new RuleTester({parserOptions});
2828
const defaultErrors = [{
29-
message: 'Using target="_blank" without rel="noopener noreferrer" is a security risk:' +
30-
' see https://mathiasbynens.github.io/rel-noopener'
29+
message: 'Using target="_blank" without rel="noreferrer" is a security risk:' +
30+
' see https://html.spec.whatwg.org/multipage/links.html#link-type-noopener'
3131
}];
3232

3333
ruleTester.run('jsx-no-target-blank', rule, {
@@ -36,18 +36,29 @@ ruleTester.run('jsx-no-target-blank', rule, {
3636
{code: '<a randomTag></a>'},
3737
{code: '<a target />'},
3838
{code: '<a href="foobar" target="_blank" rel="noopener noreferrer"></a>'},
39+
{code: '<a href="foobar" target="_blank" rel="noreferrer"></a>'},
3940
{code: '<a href="foobar" target="_blank" rel={"noopener noreferrer"}></a>'},
41+
{code: '<a href="foobar" target="_blank" rel={"noreferrer"}></a>'},
4042
{code: '<a href={"foobar"} target={"_blank"} rel={"noopener noreferrer"}></a>'},
43+
{code: '<a href={"foobar"} target={"_blank"} rel={"noreferrer"}></a>'},
4144
{code: '<a href={\'foobar\'} target={\'_blank\'} rel={\'noopener noreferrer\'}></a>'},
45+
{code: '<a href={\'foobar\'} target={\'_blank\'} rel={\'noreferrer\'}></a>'},
4246
{code: '<a href={`foobar`} target={`_blank`} rel={`noopener noreferrer`}></a>'},
47+
{code: '<a href={`foobar`} target={`_blank`} rel={`noreferrer`}></a>'},
4348
{code: '<a target="_blank" {...spreadProps} rel="noopener noreferrer"></a>'},
49+
{code: '<a target="_blank" {...spreadProps} rel="noreferrer"></a>'},
4450
{code: '<a {...spreadProps} target="_blank" rel="noopener noreferrer" href="http://example.com">s</a>'},
51+
{code: '<a {...spreadProps} target="_blank" rel="noreferrer" href="http://example.com">s</a>'},
4552
{code: '<a target="_blank" rel="noopener noreferrer" {...spreadProps}></a>'},
53+
{code: '<a target="_blank" rel="noreferrer" {...spreadProps}></a>'},
4654
{code: '<p target="_blank"></p>'},
4755
{code: '<a href="foobar" target="_BLANK" rel="NOOPENER noreferrer"></a>'},
56+
{code: '<a href="foobar" target="_BLANK" rel="NOREFERRER"></a>'},
4857
{code: '<a target="_blank" rel={relValue}></a>'},
4958
{code: '<a target={targetValue} rel="noopener noreferrer"></a>'},
59+
{code: '<a target={targetValue} rel="noreferrer"></a>'},
5060
{code: '<a target={targetValue} rel={"noopener noreferrer"}></a>'},
61+
{code: '<a target={targetValue} rel={"noreferrer"}></a>'},
5162
{code: '<a target={targetValue} href="relative/path"></a>'},
5263
{code: '<a target={targetValue} href="/absolute/path"></a>'},
5364
{code: '<a target={\'targetValue\'} href="/absolute/path"></a>'},
@@ -89,6 +100,9 @@ ruleTester.run('jsx-no-target-blank', rule, {
89100
}, {
90101
code: '<a target="_blank" rel="noopenernoreferrer" href="http://example.com"></a>',
91102
errors: defaultErrors
103+
}, {
104+
code: '<a target="_blank" rel="no referrer" href="http://example.com"></a>',
105+
errors: defaultErrors
92106
}, {
93107
code: '<a target="_BLANK" href="http://example.com"></a>',
94108
errors: defaultErrors

0 commit comments

Comments
 (0)