[The vulnerability](https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-stored) lies in how the application attempts to sanitize comment content using a **broken custom `escapeHTML()` function**, which is then injected into the DOM using `.innerHTML`. The result is a **persistent DOM-based XSS** triggered upon page load. --- ##### Vulnerable Code Path Breakdown From `loadCommentsWithVulnerableEscapeHtml.js`: ```javascript function escapeHTML(html) { return html.replace('<', '&lt;').replace('>', '&gt;'); } ``` ##### ❗ Critical Flaw: - `String.prototype.replace()` with a **string** pattern (e.g. `replace('<', ...)`) replaces **only the first occurrence**. - This allows bypassing the intended sanitization by **introducing multiple angle brackets**. Where is it? `resources/js/loadCommentsWithVulnerableEscapeHtml.js` --- ##### Exploitable Sink ```javascript commentBodyPElement.innerHTML = escapeHTML(comment.body); ``` - The sanitized (but incompletely encoded) `comment.body` is assigned directly into `innerHTML` — an unsafe sink. - DOM parses remaining unescaped characters (e.g., `<img>`), triggering script execution. --- ##### Final Exploit Payload ```html <><img src=1 onerror=alert(1)> ``` - The **first `<` is encoded** into `&lt;` - The **second `<img>` is not encoded**, due to faulty `.replace('<', ...)` - When `.innerHTML` is assigned, the `<img>` tag is parsed and executed --- ##### Key Vulnerability Attributes | Property | Detail | | ------------------ | ----------------------------------------------------------------------------- | | **Type** | Stored DOM-based XSS | | **Attack Surface** | `comment.body` field | | **Vector** | HTML tag injection via malformed escaping | | **Sink** | `.innerHTML` | | **Root Cause** | Improper use of `.replace()` without RegExp and assigning directly to the DOM | | **Persistence** | Yes — payload is stored and triggered on page load for all users |