Write-Up by Aditya Bhatt | DOM-Based XSS | jQuery Attribute Injection | BurpSuite
Lab Link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-href-attribute-sink
Lab: DOM XSS in jQuery anchor href attribute sink using location.search source
This PortSwigger lab contains a DOM XSS vulnerability inside the Submit Feedback page.
The JavaScript takes user input from location.search, feeds it into jQuery's $() selector, and dynamically updates the anchor tag’s href attribute — making it vulnerable to attribute-based JavaScript execution.
We begin by loading the lab to examine how the feedback page uses the returnPath parameter.
➤ Why? Understanding where the data flows from the URL helps confirm whether the sink is manipulable.
The URL looks like:
?returnPath=/
This pattern hints that the application dynamically modifies the Back link based on this parameter.
➤ Why?
Any parameter that controls attributes like href, src, or action is a prime XSS candidate.
After testing with “hii”, we find the DOM reflects it as:
<a id="backlink" href="/hii">Back</a>
➤ Why?
This confirms location.search → jQuery.attr("href"), a dangerous pattern because browsers execute JavaScript when href starts with javascript:.
javascript:alert(document.cookie)
➤ Why this payload works?
- Browsers allow URLs starting with
javascript:insidehrefattributes. - Clicking such a link executes the JavaScript directly.
- Since jQuery blindly injects user-controlled data into
.attr("href", ...), it becomes executable code.
This lets us run:
alert(document.cookie)
which proves DOM XSS.
➤ Why? The link no longer points to a webpage — it now executes JavaScript when clicked, thanks to our crafted payload.
javascript:alert(document.cookie)
- The
javascript:protocol turns an anchor click into script execution. - Browsers interpret everything after it as inline JavaScript.
- With DOM sinks like jQuery
.attr(), this is one of the simplest ways to weaponize XSS.
| Payload | Trigger | Suitable For | Notes |
|---|---|---|---|
<svg onload=alert(1)> |
Auto fires on parsing | innerHTML, HTML injection | Great when HTML is parsed |
<img src=1 onerror=alert(1)> |
Fires on load error | HTML injection, stored/reflected | Universal payload |
javascript:alert(document.cookie) |
Fires on click | Attribute-based XSS (href, src) |
Perfect for attribute sinks, especially jQuery |
This lab uses an href attribute sink, so the most effective payload is javascript: over HTML tag payloads.
DOM XSS of this type is extremely common in modern JavaScript-heavy apps.
- Can steal session cookies
- Can perform account takeover
- Can redirect users to phishing pages
- Works even when backend validation is perfect
- Harder for WAFs to detect because no request contains malicious script output
- jQuery’s
$()processes attacker-controlled selectors .attr()populateshref,src,data-*,action,onclickattributes- URL parameters directly influence UI behavior (like "redirect" links)
-
Unsafe JavaScript Sink
$("#backlink").attr("href", userInput); -
Unsafe Source
userInput = location.search -
jQuery automatically treats attribute values as literal strings, not sanitized ones.
-
The browser interprets
javascript:URLs as executable JavaScript.
Result → full DOM XSS.
Allow only known safe paths like /home, /feedback.
Block anything starting with:
javascript:
data:
vbscript:
Sanitize everything coming from URL parameters before injecting into the DOM.
Instead, use server-side verified redirects.
This lab showcases a classic jQuery-based DOM XSS where user-controlled input manipulates an anchor’s href attribute.
By injecting a javascript: protocol, attackers can turn a normal link into an executable payload — leading to full DOM XSS.
Short, simple, and extremely common in bug bounty programs.
Stay curious. Stay offensive.
— Aditya Bhatt 🔥





