DOM BASED
What is the DOM?
The Document Object Model (DOM) is a web browser's hierarchical representation of the elements on the page.
Websites use JavaScript to manipulate the nodes and objects of the DOM and their properties.
JavaScript that handles data insecurely can enable various attacks.
DOM-based vulnerabilities arise when a website contains JavaScript that takes an attacker-controllable value and passes it into a dangerous function (a sink).
DOM-based cross-site scripting
This arises when an application contains some client-side JavaScript that processes data from an untrusted source in an unsafe way and writes the data to the DOM.
Example:
var search = document.getElementById('search').value;
var results = document.getElementById('results');
results.innerHTML = 'You searched for: ' + search;This can be attacked with a malicious value that causes script to execute. For example: You searched for:
In most cases the input field would be populated from part of the HTTP request, e.g. a URL query string parameter.
Taint-flow vulnerabilities
Many DOM-based vulnerabilities can be traced back to problems in how client-side code manipulates attacker-controllable data.
What is Taint flow?
Taint flow involves tracking potentially unsafe or untrusted data as it moves through a program to ensure it does not reach sensitive parts of the system.
Sources
JavaScript properties that accept potentially attacker-controlled data:
location.search(reads inputs from the query string)document.referrerdocument.cookieweb messages, etc.
Sinks
Potentially dangerous JavaScript functions or DOM objects that can cause undesirable effects if attacker-controlled data is passed to them:
eval()(executes argument as JavaScript)HTML sinks like
document.body.innerHTML(allows injection of malicious HTML and execution of arbitrary JavaScript)
DOM-based vulnerabilities arise when data flows from a source to a sink in an unsafe way.
Example showing unsafe handling of location.hash:
Vulnerable because
location.hashis attacker-controllable and is used unsafely to setlocation, allowing redirection to an attacker-controlled site.
Common sources (examples):
DOM-based XSS
DOM-based XSS occurs when JavaScript takes data from an attacker-controllable source (e.g., URL) and passes it to a sink that supports dynamic code execution (e.g.,
eval()orinnerHTML), enabling an attacker to execute malicious JavaScript (e.g., hijack user accounts).
Labs (each lab is presented as a stepper)
Lab: DOM XSS in document.write sink using source location.search — Overview
Target: QuickSearch (Web_Pentest730). The site displays search results dynamically and insecurely writes search queries directly to the webpage using
document.write(). Input is taken fromlocation.search, making it vulnerable to DOM-based XSS.
Goal: Inject HTML/JavaScript into the page by modifying the URL.
Why the exploit works & impact
Breaking out of the attribute context:
">closes<img>tag allowing new elements.document.write()writes input as-is—dangerous if unsanitized.location.searchis attacker-controlled.Real-world impact: account hijacking (steal
document.cookie), phishing (fake forms), malware distribution.
Lab: DOM XSS in document.write sink using source location.search inside a select element — Overview
Target: Online shopping platform (Web_Pentest731).
storeIdparameter from URL is added as an<option>inside a<select>viadocument.write()without sanitization.Goal: Break out of
<select>, inject HTML/JS, trigger an alert.
Attack / Payload
Payload:
"></select><img src=1 onerror=alert(1)>">closes the<option>.</select>closes the<select>.<img src=1 onerror=alert(1)>injects an image that fails to load and triggersonerror.
Malicious URL:
https://YOUR-LAB-ID.web-security-academy.net/product?productId=1&storeId="></select><img%20src=1%20onerror=alert(1)>
Lab: DOM XSS in jQuery selector sink using a hashchange event — Overview
Target: Site uses
$(location.hash)to scroll to posts based on URL hash and listens forhashchange.Vulnerability:
$(location.hash)uses attacker-controlled hash in jQuery selector, enabling injection.Goal: Cause execution of
print()via an injected payload in the hash using an iframe exploit.
Lab: DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded — Overview
Target: AngularJS-based site (Web_Pentest732) where search input is evaluated as an AngularJS expression inside
{{ }}.Challenge: Angle brackets
<and>are encoded, so classic tag-based payloads won't work.Goal: Execute JavaScript via AngularJS expression.
Lab: Stored DOM XSS — Overview
Target: Blog site (Web_Pentest74) storing comments. A comment is stored on server and later inserted into the DOM client-side unsafely. The site attempts to encode angle brackets but only replaces the first occurrence.
Goal: Bypass the single-replacement encoding and execute JavaScript.
Common sinks that can lead to DOM-XSS vulnerabilities
jQuery functions that are also sinks
WEB DOM CLOBBERING
Analogy: A JavaScript program is a party and variables are people wearing name tags. If an attacker injects an HTML element with an id/name that matches a global variable, the browser may resolve that global to the DOM node instead of the intended JS object.
Example vulnerable code:
Attacker injection:
window.someObjectbecomes the DOM node (the<a>), sosomeObject.urlpoints to the link'surl/nameproperty, and a script is loaded from the attacker-controlled URL.
Dom clobbering is overwriting a JavaScript variable with a DOM element, often to trick the app into behaving unexpectedly.
How to find & test clobbering
Look for code patterns like
window.xyz || {}or global variables used without strict checks.Check places where HTML injection is possible (profile pages, comments, forums).
Try injecting elements with id/name matching global variable names:
Observe whether scripts/resources are loaded from attacker domains or behavior changes.
In DevTools: inspect
console.log(window.someObject)after injection to see if it's a DOM node.
Lab: DOM-clobbering → Attribute injection → XSS
1. Lab Introduction
Feature: Comments that allow limited HTML anchors and render avatars using
defaultAvatar.avatar.Attack vector: DOM clobbering via anchors sharing the same id, combined with attribute values that decode at runtime (e.g.,
") to break attribute syntax and inject anonerrorhandler.Techniques: DOM clobbering, attribute injection, unsafe client-side string concatenation /
innerHTML.
2. Reconnaissance plan
Find comment posting pages allowing minimal HTML (e.g.,
<a>,<img>).Check sanitizer rules: can you include
id,name, encoded quotes like",cid:protocols?Search client scripts for
window.someVar || {}patterns, e.g.,let defaultAvatar = window.defaultAvatar || {...}.Check whether avatars are injected via
innerHTMLorimg.src.
3. Vulnerability — Problem
Source: reliance on global
window.defaultAvatar || {avatar: '...'}combined with user-controlled HTML that can createid/namecolliding with globals.Sink: unsafe HTML construction such as:
Sanitizer allows
id/name,cid:protocol and"sequences that decode into quotes at runtime.
5. Attack (first attempt) — Payloads
Comment #1 (clobber):
Two
<a>elements shareid=defaultAvatarsowindow.defaultAvatarrefers to the DOM collection/element.Second anchor has
name=avatarandhref="cid:"onerror=alert(1)//". When"decodes to", it can break attribute syntax later and injectonerror.
6. Exploit & Trigger
Post Comment #1 (the two anchors).
Post Comment #2 (e.g., "Nice post!") to trigger re-render of comments.
Client executes code like:
With
window.defaultAvatarclobbered,defaultAvatar.avatarresolves tocid:"onerror=alert(1)//.Constructed HTML becomes:
Browser parses the broken attribute, image load fails,
onerrorfires →alert(1).
7. Enumeration
Confirm comments accept minimal HTML and
id/name.Locate client code patterns like
window.X || {}.Verify avatar rendering uses
innerHTML/ unsafe templating.Test sanitizer: does it allow
cid:and"?Use DevTools to inspect
window.defaultAvatarafter comment #1 to confirm clobbering.
8. Final payload & notes
Comment #1 (clobber):
Comment #2 (trigger):
Nice post!Single-line variant:
Why it works:
id=defaultAvatarclobbers JS variable.name=avatarprovides.avatarproperty on the DOM collection."decodes to"and breakssrc="...", insertingonerror.Unsafe
innerHTMLconcatenation results in a parsed element withonerror.
Real-world impact:
Look for
window.X || {}patterns and sanitizer allowances (cid:,").Clobbering can lead to script execution even when ordinary XSS vectors are filtered.
How to Prevent DOM-Based XSS (summary)
Avoid using dangerous sinks like
document.write()where possible. Prefer safe DOM APIs:Use
textContent,innerText, or set properties likeelement.srcinstead ofinnerHTML/string templating.
Sanitize and encode user inputs appropriately for the context where they will be used.
Implement a strong Content Security Policy (CSP) to limit sources of executable scripts and reduce XSS impact.
Avoid relying on global variables that can be clobbered; validate and tightly control values used to build HTML.
Last updated