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
Aprende a encontrar este bug
Este bug pagó $750 en HackerOne.
Crea tu cuenta y practica bugs reales que se pagaron. Descarga el entorno, encuéntralo y aprende la técnica exacta — tu camino a tu primer bounty.
hunters entrenando
labs de reportes reales
completaciones
en bounties practicados
Acceso a todos los labs · sin permanencia · cancela cuando quieras
Hunters que lo han resuelto· 8
Objetivos
Logro que recibirás
Cuando resuelvas este lab desbloqueas este logro compartible
self_svg_XSS — Self-XSS → Bot-Assisted ATO via SVG upload
Writeups de la comunidad
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…}