Skip to content

Commit c7c6c05

Browse files
jleveugletanhauhau
andauthored
[feat] add security warning for anchor element (rel attribute) (#6289)
* add security warning for anchor element (rel attribute) * manage more case for security warnings on anchor (aplocks, false positive ...) * remove noopener checks as noreferrer imples noopener Co-authored-by: tanhauhau <[email protected]>
1 parent ea9ee39 commit c7c6c05

File tree

3 files changed

+323
-0
lines changed

3 files changed

+323
-0
lines changed

src/compiler/compile/nodes/Element.ts

+20
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,26 @@ export default class Element extends Node {
613613
const href_attribute = attribute_map.get('href') || attribute_map.get('xlink:href');
614614
const id_attribute = attribute_map.get('id');
615615
const name_attribute = attribute_map.get('name');
616+
const target_attribute = attribute_map.get('target');
617+
618+
if (target_attribute && target_attribute.get_static_value() === '_blank' && href_attribute) {
619+
const href_static_value = href_attribute.get_static_value() ? href_attribute.get_static_value().toLowerCase() : null;
620+
621+
if (href_static_value === null || href_static_value.match(/^(https?:)?\/\//i)) {
622+
const rel = attribute_map.get('rel');
623+
const rel_values = rel ? rel.get_static_value().split(' ') : [];
624+
const expected_values = ['noreferrer'];
625+
626+
expected_values.forEach(expected_value => {
627+
if (!rel || rel && rel_values.indexOf(expected_value) < 0) {
628+
component.warn(this, {
629+
code: `security-anchor-rel-${expected_value}`,
630+
message: `Security: Anchor with "target=_blank" should have rel attribute containing the value "${expected_value}"`
631+
});
632+
}
633+
});
634+
}
635+
}
616636

617637
if (href_attribute) {
618638
const href_value = href_attribute.get_static_value();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<a href="https://svelte.dev" target="_blank">svelte website (invalid)</a>
2+
<a href="https://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
3+
<a href="https://svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
4+
<a href={'https://svelte.dev'} target="_blank">svelte website (invalid)</a>
5+
<a href={'https://svelte.dev'} target="_blank" rel="">svelte website (invalid)</a>
6+
<a href={'https://svelte.dev'} target="_blank" rel="noopener">svelte website (invalid)</a>
7+
<a href="//svelte.dev" target="_blank">svelte website (invalid)</a>
8+
<a href="//svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
9+
<a href="//svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
10+
<a href="http://svelte.dev" target="_blank">svelte website (invalid)</a>
11+
<a href="http://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
12+
<a href="http://svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
13+
<a href="HTTP://svelte.dev" target="_blank">svelte website (invalid)</a>
14+
<a href="HTTP://svelte.dev" target="_blank" rel="">svelte website (invalid)</a>
15+
<a href="HTTP://svelte.dev" target="_blank" rel="noopener">svelte website (invalid)</a>
16+
<a href={'HTTPS://svelte.dev'} target="_blank">svelte website (invalid)</a>
17+
<a href={'HTTPS://svelte.dev'} target="_blank" rel="">svelte website (invalid)</a>
18+
<a href={'HTTPS://svelte.dev'} target="_blank" rel="noopener">svelte website (invalid)</a>
19+
<a href="same-host" target="_blank">Same host (valid)</a>
20+
<a href="same-host" target="_blank" rel="">Same host (valid)</a>
21+
<a href="same-host" target="_blank" rel="noopener">Same host (valid)</a>
22+
<a href="http://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
23+
<a href="http://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
24+
<a href="HTTP://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
25+
<a href="HTTP://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
26+
<a href="https://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
27+
<a href="https://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
28+
<a href="HTTPS://svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
29+
<a href="HTTPS://svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
30+
<a href="//svelte.dev" target="_blank" rel="noreferrer">svelte website (valid)</a>
31+
<a href="//svelte.dev" target="_blank" rel="noreferrer noopener">svelte website (valid)</a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
[
2+
{
3+
"code": "security-anchor-rel-noreferrer",
4+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
5+
"end": {
6+
"character": 73,
7+
"column": 73,
8+
"line": 1
9+
},
10+
"pos": 0,
11+
"start": {
12+
"character": 0,
13+
"column": 0,
14+
"line": 1
15+
}
16+
},
17+
{
18+
"code": "security-anchor-rel-noreferrer",
19+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
20+
"end": {
21+
"character": 154,
22+
"column": 80,
23+
"line": 2
24+
},
25+
"pos": 74,
26+
"start": {
27+
"character": 74,
28+
"column": 0,
29+
"line": 2
30+
}
31+
},
32+
{
33+
"code": "security-anchor-rel-noreferrer",
34+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
35+
"end": {
36+
"character": 243,
37+
"column": 88,
38+
"line": 3
39+
},
40+
"pos": 155,
41+
"start": {
42+
"character": 155,
43+
"column": 0,
44+
"line": 3
45+
}
46+
},
47+
{
48+
"code": "security-anchor-rel-noreferrer",
49+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
50+
"end": {
51+
"character": 319,
52+
"column": 75,
53+
"line": 4
54+
},
55+
"pos": 244,
56+
"start": {
57+
"character": 244,
58+
"column": 0,
59+
"line": 4
60+
}
61+
},
62+
{
63+
"code": "security-anchor-rel-noreferrer",
64+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
65+
"end": {
66+
"character": 402,
67+
"column": 82,
68+
"line": 5
69+
},
70+
"pos": 320,
71+
"start": {
72+
"character": 320,
73+
"column": 0,
74+
"line": 5
75+
}
76+
},
77+
{
78+
"code": "security-anchor-rel-noreferrer",
79+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
80+
"end": {
81+
"character": 493,
82+
"column": 90,
83+
"line": 6
84+
},
85+
"pos": 403,
86+
"start": {
87+
"character": 403,
88+
"column": 0,
89+
"line": 6
90+
}
91+
},
92+
{
93+
"code": "security-anchor-rel-noreferrer",
94+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
95+
"end": {
96+
"character": 561,
97+
"column": 67,
98+
"line": 7
99+
},
100+
"pos": 494,
101+
"start": {
102+
"character": 494,
103+
"column": 0,
104+
"line": 7
105+
}
106+
},
107+
{
108+
"code": "security-anchor-rel-noreferrer",
109+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
110+
"end": {
111+
"character": 636,
112+
"column": 74,
113+
"line": 8
114+
},
115+
"pos": 562,
116+
"start": {
117+
"character": 562,
118+
"column": 0,
119+
"line": 8
120+
}
121+
},
122+
{
123+
"code": "security-anchor-rel-noreferrer",
124+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
125+
"end": {
126+
"character": 719,
127+
"column": 82,
128+
"line": 9
129+
},
130+
"pos": 637,
131+
"start": {
132+
"character": 637,
133+
"column": 0,
134+
"line": 9
135+
}
136+
},
137+
{
138+
"code": "security-anchor-rel-noreferrer",
139+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
140+
"end": {
141+
"character": 792,
142+
"column": 72,
143+
"line": 10
144+
},
145+
"pos": 720,
146+
"start": {
147+
"character": 720,
148+
"column": 0,
149+
"line": 10
150+
}
151+
},
152+
{
153+
"code": "security-anchor-rel-noreferrer",
154+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
155+
"end": {
156+
"character": 872,
157+
"column": 79,
158+
"line": 11
159+
},
160+
"pos": 793,
161+
"start": {
162+
"character": 793,
163+
"column": 0,
164+
"line": 11
165+
}
166+
},
167+
{
168+
"code": "security-anchor-rel-noreferrer",
169+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
170+
"end": {
171+
"character": 960,
172+
"column": 87,
173+
"line": 12
174+
},
175+
"pos": 873,
176+
"start": {
177+
"character": 873,
178+
"column": 0,
179+
"line": 12
180+
}
181+
},
182+
{
183+
"code": "security-anchor-rel-noreferrer",
184+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
185+
"end": {
186+
"character": 1033,
187+
"column": 72,
188+
"line": 13
189+
},
190+
"pos": 961,
191+
"start": {
192+
"character": 961,
193+
"column": 0,
194+
"line": 13
195+
}
196+
},
197+
{
198+
"code": "security-anchor-rel-noreferrer",
199+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
200+
"end": {
201+
"character": 1113,
202+
"column": 79,
203+
"line": 14
204+
},
205+
"pos": 1034,
206+
"start": {
207+
"character": 1034,
208+
"column": 0,
209+
"line": 14
210+
}
211+
},
212+
{
213+
"code": "security-anchor-rel-noreferrer",
214+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
215+
"end": {
216+
"character": 1201,
217+
"column": 87,
218+
"line": 15
219+
},
220+
"pos": 1114,
221+
"start": {
222+
"character": 1114,
223+
"column": 0,
224+
"line": 15
225+
}
226+
},
227+
{
228+
"code": "security-anchor-rel-noreferrer",
229+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
230+
"end": {
231+
"character": 1277,
232+
"column": 75,
233+
"line": 16
234+
},
235+
"pos": 1202,
236+
"start": {
237+
"character": 1202,
238+
"column": 0,
239+
"line": 16
240+
}
241+
},
242+
{
243+
"code": "security-anchor-rel-noreferrer",
244+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
245+
"end": {
246+
"character": 1360,
247+
"column": 82,
248+
"line": 17
249+
},
250+
"pos": 1278,
251+
"start": {
252+
"character": 1278,
253+
"column": 0,
254+
"line": 17
255+
}
256+
},
257+
{
258+
"code": "security-anchor-rel-noreferrer",
259+
"message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"",
260+
"end": {
261+
"character": 1451,
262+
"column": 90,
263+
"line": 18
264+
},
265+
"pos": 1361,
266+
"start": {
267+
"character": 1361,
268+
"column": 0,
269+
"line": 18
270+
}
271+
}
272+
]

0 commit comments

Comments
 (0)