Skip to content

Commit fb0d661

Browse files
committed
add security warning for anchor element (rel attribute)
1 parent 086cff2 commit fb0d661

File tree

5 files changed

+452
-0
lines changed

5 files changed

+452
-0
lines changed

src/compiler/compile/nodes/Element.ts

+20
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,26 @@ export default class Element extends Node {
451451
const href_attribute = attribute_map.get('href') || attribute_map.get('xlink:href');
452452
const id_attribute = attribute_map.get('id');
453453
const name_attribute = attribute_map.get('name');
454+
const target_attribute = attribute_map.get('target');
455+
456+
if (target_attribute && target_attribute.get_static_value() === '_blank' && href_attribute) {
457+
const href_static_value = href_attribute.get_static_value() ? href_attribute.get_static_value().toLowerCase() : null;
458+
459+
if (href_static_value === null || href_static_value.startsWith('http') || href_static_value.startsWith('//')) {
460+
const rel = attribute_map.get('rel');
461+
const rel_values = rel ? rel.get_static_value().split(' ') : [];
462+
const expected_values = ['noopener', 'noreferrer'];
463+
464+
expected_values.forEach(expected_value => {
465+
if (!rel || rel && rel_values.indexOf(expected_value) < 0) {
466+
component.warn(this, {
467+
code: `security-anchor-rel-${expected_value}`,
468+
message: `Security: Anchor with "target=_blank" should have rel attribute containing the value "${expected_value}"`
469+
});
470+
}
471+
});
472+
}
473+
}
454474

455475
if (href_attribute) {
456476
const href_value = href_attribute.get_static_value();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
2+
<a href="https://svelte.dev" target="_blank">svelte website (invalid)</a>
3+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
4+
<a href="https://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
5+
<a href="https://svelte.dev" target="_blank" rel="noreferrer">svelte website (invalid)</a>
6+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
7+
<a href={'https://svelte.dev'} target="_blank">svelte website (invalid)</a>
8+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
9+
<a href={'https://svelte.dev'} target="_blank" rel="">svelte website (invalid)</a>
10+
<a href={'https://svelte.dev'} target="_blank" rel="noreferrer">svelte website (invalid)</a>
11+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
12+
<a href="//svelte.dev" target="_blank">svelte website (invalid)</a>
13+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
14+
<a href="//svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
15+
<a href="//svelte.dev" target="_blank" rel="noreferrer">svelte website (invalid)</a>
16+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
17+
<a href="http://svelte.dev" target="_blank">svelte website (invalid)</a>
18+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
19+
<a href="http://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
20+
<a href="http://svelte.dev" target="_blank" rel="noreferrer">svelte website (invalid)</a>
21+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
22+
<a href="same-host" target="_blank">Same host (valid)</a>
23+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
24+
<a href="same-host" target="_blank" rel="">Same host (valid)</a>
25+
<a href="same-host" target="_blank" rel="noreferrer">Same host (valid)</a>
26+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
27+
<a href="http://svelte.dev" target="_blank" rel="noopener">svelte website (valid)</a>
28+
<a href="http://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
29+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
30+
<a href="https://svelte.dev" target="_blank" rel="noopener">svelte website (valid)</a>
31+
<a href="https://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
32+
<!-- svelte-ignore security-anchor-rel-noreferrer -->
33+
<a href="//svelte.dev" target="_blank" rel="noopener">svelte website (valid)</a>
34+
<a href="//svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
[
2+
{
3+
"code": "security-anchor-rel-noopener",
4+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
5+
"start": {
6+
"line": 2,
7+
"column": 0,
8+
"character": 54
9+
},
10+
"end": {
11+
"line": 2,
12+
"column": 73,
13+
"character": 127
14+
},
15+
"pos": 54
16+
},
17+
{
18+
"code": "security-anchor-rel-noopener",
19+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
20+
"start": {
21+
"line": 4,
22+
"column": 0,
23+
"character": 182
24+
},
25+
"end": {
26+
"line": 4,
27+
"column": 80,
28+
"character": 262
29+
},
30+
"pos": 182
31+
},
32+
{
33+
"code": "security-anchor-rel-noopener",
34+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
35+
"start": {
36+
"line": 5,
37+
"column": 0,
38+
"character": 263
39+
},
40+
"end": {
41+
"line": 5,
42+
"column": 90,
43+
"character": 353
44+
},
45+
"pos": 263
46+
},
47+
{
48+
"code": "security-anchor-rel-noopener",
49+
"end": {
50+
"character": 483,
51+
"column": 75,
52+
"line": 7
53+
},
54+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
55+
"pos": 408,
56+
"start": {
57+
"character": 408,
58+
"column": 0,
59+
"line": 7
60+
}
61+
},
62+
{
63+
"code": "security-anchor-rel-noopener",
64+
"end": {
65+
"character": 620,
66+
"column": 82,
67+
"line": 9
68+
},
69+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
70+
"pos": 538,
71+
"start": {
72+
"character": 538,
73+
"column": 0,
74+
"line": 9
75+
}
76+
},
77+
{
78+
"code": "security-anchor-rel-noopener",
79+
"end": {
80+
"character": 713,
81+
"column": 92,
82+
"line": 10
83+
},
84+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
85+
"pos": 621,
86+
"start": {
87+
"character": 621,
88+
"column": 0,
89+
"line": 10
90+
}
91+
},
92+
{
93+
"code": "security-anchor-rel-noopener",
94+
"end": {
95+
"character": 835,
96+
"column": 67,
97+
"line": 12
98+
},
99+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
100+
"pos": 768,
101+
"start": {
102+
"character": 768,
103+
"column": 0,
104+
"line": 12
105+
}
106+
},
107+
{
108+
"code": "security-anchor-rel-noopener",
109+
"end": {
110+
"character": 964,
111+
"column": 74,
112+
"line": 14
113+
},
114+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
115+
"pos": 890,
116+
"start": {
117+
"character": 890,
118+
"column": 0,
119+
"line": 14
120+
}
121+
},
122+
{
123+
"code": "security-anchor-rel-noopener",
124+
"end": {
125+
"character": 1049,
126+
"column": 84,
127+
"line": 15
128+
},
129+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
130+
"pos": 965,
131+
"start": {
132+
"character": 965,
133+
"column": 0,
134+
"line": 15
135+
}
136+
},
137+
{
138+
"code": "security-anchor-rel-noopener",
139+
"end": {
140+
"character": 1176,
141+
"column": 72,
142+
"line": 17
143+
},
144+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
145+
"pos": 1104,
146+
"start": {
147+
"character": 1104,
148+
"column": 0,
149+
"line": 17
150+
}
151+
},
152+
{
153+
"code": "security-anchor-rel-noopener",
154+
"end": {
155+
"character": 1310,
156+
"column": 79,
157+
"line": 19
158+
},
159+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
160+
"pos": 1231,
161+
"start": {
162+
"character": 1231,
163+
"column": 0,
164+
"line": 19
165+
}
166+
},
167+
{
168+
"code": "security-anchor-rel-noopener",
169+
"end": {
170+
"character": 1400,
171+
"column": 89,
172+
"line": 20
173+
},
174+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"",
175+
"pos": 1311,
176+
"start": {
177+
"character": 1311,
178+
"column": 0,
179+
"line": 20
180+
}
181+
}
182+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!-- svelte-ignore security-anchor-rel-noopener -->
2+
<a href="https://svelte.dev" target="_blank">svelte website (invalid)</a>
3+
<!-- svelte-ignore security-anchor-rel-noopener -->
4+
<a href="https://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
5+
<a href="https://svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
6+
<!-- svelte-ignore security-anchor-rel-noopener -->
7+
<a href={'https://svelte.dev'} target="_blank">svelte website (invalid)</a>
8+
<!-- svelte-ignore security-anchor-rel-noopener -->
9+
<a href={'https://svelte.dev'} target="_blank" rel="">svelte website (invalid)</a>
10+
<a href={'https://svelte.dev'} target="_blank" rel="noopener">svelte website (invalid)</a>
11+
<!-- svelte-ignore security-anchor-rel-noopener -->
12+
<a href="//svelte.dev" target="_blank">svelte website (invalid)</a>
13+
<!-- svelte-ignore security-anchor-rel-noopener -->
14+
<a href="//svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
15+
<a href="//svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
16+
<!-- svelte-ignore security-anchor-rel-noopener -->
17+
<a href="http://svelte.dev" target="_blank">svelte website (invalid)</a>
18+
<!-- svelte-ignore security-anchor-rel-noopener -->
19+
<a href="http://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
20+
<a href="http://svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
21+
<!-- svelte-ignore security-anchor-rel-noopener -->
22+
<a href="same-host" target="_blank">Same host (valid)</a>
23+
<!-- svelte-ignore security-anchor-rel-noopener -->
24+
<a href="same-host" target="_blank" rel="">Same host (valid)</a>
25+
<a href="same-host" target="_blank" rel="noopener">Same host (valid)</a>
26+
<!-- svelte-ignore security-anchor-rel-noopener -->
27+
<a href="http://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
28+
<a href="http://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
29+
<!-- svelte-ignore security-anchor-rel-noopener -->
30+
<a href="https://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
31+
<a href="https://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
32+
<!-- svelte-ignore security-anchor-rel-noopener -->
33+
<a href="//svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
34+
<a href="//svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>

0 commit comments

Comments
 (0)