[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('<', '<').replace('>', '>');
}
```
##### ❗ 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 `<`
- 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 |