PortSwigger-Writeups

Lab: Reflected XSS in Canonical Link Tag

Lab Difficulty: Apprentice

Topic: Cross-Site Scripting (Reflected)

1. Objective

The objective of this lab is to perform a Reflected Cross-Site Scripting (XSS) attack. The vulnerability exists within the HTML <link> tag used for canonical URL definition. The goal is to inject a payload that executes the alert function.

c1

2. Reconnaissance & Analysis

Identification of Reflection Point

We started by navigating to the blog posts and observing how the URL parameters affect the HTML source. The application uses a “canonical” link tag to help search engines understand the preffered URL for a page.

Upon inspecting the source code for a post (e.g., /post?postId=4), we noticed that the entire URL, including query parameters, is reflected inside the href attribute of the <link rel="canonical"> tag.

c2

Vulnerability Assessment

The reflection occurs inside a single-quoted string:

<link rel="canonical" href='.../post?postId=4'/>

If the application fails to sanitise single quotes, we can break out of the href attribute. However, since this tag resides in the <head> section of the HTML document and is not a visible element, standard event handlers like onmouseover or onfocus will not trigger automatically or via mouse interaction.

To exploit this, we need an attribute that allows user interaction via the keyboard. The accesskey attribute is suitable here, as it allows us to assign a keyboard shortcut to the element.

3. Exploitation

Payload Construction

We crafted a payload to:

  1. Break Out: Use a single quote ' to close the href attribute.

  2. Add Interaction: Inject the accesskey='x' attribute. This allows us to target the hidden element by pressing a key combination (e.g., ALT+X on Windows, CTRL+ALT+X on macOS).

  3. Add Trigger: Inject onclick='alert(1)'. When the access key is pressed, the “click” event fires, executing our JavaScript.

Payload:

' accesskey='x' onclick='alert(1)

Full URL:

/?postId=3&x=' accesskey='x' onclick='alert(1)

Execution

We sent the request via Burp Suite to verify the injection structure.

c3 c4

As seen in the response:

<link rel="canonical" href='...postId=3&x=' accesskey='x' onclick='alert(1)'/>