self_svg_XSS — Self-XSS → Bot-Assisted ATO via SVG upload
Chain an SVG upload, a `blob:` URL, a chat invite and a headless admin helper bot to turn a Self-XSS into full admin account takeover
Learn to find this bug
This bug paid $750 on HackerOne.
Create your account and practice real bugs that got paid. Download the environment, find it and learn the exact technique — your path to your first bounty.
hunters training
labs from real hacks
completions
paid out for these bugs
Access to all labs · no commitment · cancel anytime
Hackers who solved it· 8
Objectives
Achievement you'll earn
Solve this lab to unlock this shareable achievement
self_svg_XSS — Self-XSS → Bot-Assisted ATO via SVG upload
Community writeups
Attack Chain
Root causes (what makes the chain work)
- Unsanitized SVG upload. The server preserves
Content-Type: image/svg+xml
and serves uploads inline (files.ts). - Top-level blob-URL open.
FileAttachment.tsxbuilds a blob URL from the
downloaded file and callswindow.open(blobUrl). A blob URL loaded as a
document inherits the creator's origin, so the SVG's<script>runs inside
NeuroChat's origin. - JWT in
localStorage.auth.tsreturns the token in the JSON response
body and the client stores it inlocalStorage['nc_token']— reachable from
any script running in the origin. - Open chat invites. Any user can invite anyone (including
admin@) into
any chat they own. - Eager admin helper. A headless Chromium bot loads the chat and clicks the
"Open in new tab" button on each attachment, firing the payload.
How to solve
1) Exploration
- Sign in as attacker, upload an SVG that visibly renders (e.g. a simple shape)
- Click Open in new tab — observe it opens on a
blob:URL - Inspect Network tab:
/api/files/:idreturnsContent-Type: image/svg+xml
2) Proof of script exec
Upload an SVG such as:
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="40">
<text y="25">hi</text>
<script>alert(document.domain)</script>
</svg>
Click Open in new tab → alert pops on localhost:1338 → Self-XSS confirmed.
3) Weaponize
Your user id is visible in any decoded JWT (or in /admin if seen, but you are
not admin yet — use atob(token.split('.')[1])). Build an SVG that POSTs your
localStorage to /api/exfil/<id> (see exploit.py).
4) Deliver
Upload the weaponized SVG to a chat. Invite admin@neurochat.ai. The bot polls
every ~15s; it will accept, visit the chat, and click the attachment.
5) Harvest
Open /stolen in the UI (or poll /api/exfil). A capture withemail = admin@neurochat.ai will appear.
6) Takeover
Click Hijack session on that capture (or copy the token intolocalStorage['nc_token']). Browse to /admin → flag.
Or: just run the exploit
python3 exploit.py
Proof of Concept (automated)
exploit.py automates steps 1–6 end-to-end. Typical run:
[1] Login as attacker@neurochat.ai
✓ logged in as #1 (Alex Morgan) · role=user
[2] Create attacker-owned chat
✓ chat id = 5
[3] Craft SVG payload (exfil → /api/exfil/1)
✓ 1.4 KB
[4] Upload dashboard-mockup.svg
✓ mime preserved as image/svg+xml
[5] Post message referencing file
[6] Invite admin@neurochat.ai
[7] Poll /api/exfil for captured admin token
✓ captured admin JWT
[8] Hit /api/admin with stolen JWT
FLAG{e7a15c…}