SVG XSS Lab: Slip Script Past a Tag-Stripping Sanitiser

✨ AI Summary
ProfilePics lets you upload an SVG as your avatar and renders it on the page. Its sanitiser strips <script> tags and calls it a day. But SVG is XML with dozens of ways to run JavaScript that are not a script tag — and the sanitiser leaves those alone.
Lab at a glance: Intermediate · 80 XP · about 15 minutes · runs in your browser, no signup or setup. Try it yourself first; the full solution is behind a spoiler below.

What this lab teaches

SVG is not just an image format; it is XML that the browser renders live, and it supports event-handler attributes and other constructs that execute JavaScript. A sanitiser that only removes <script> tags misses all of those, so an uploaded SVG can still run code in the victim's browser — stored or reflected XSS through an image.

The lesson: blocklist sanitisers that strip 'known bad' patterns always miss something. SVG has too many execution paths to enumerate.

How ProfilePics sanitises your avatar

When you set an SVG avatar, ProfilePics removes script tags and then renders the SVG inline. Because it only targets that one pattern, an SVG element carrying an event-handler attribute survives, and the handler runs when the image loads or is interacted with.

The attack approach

  • Confirm SVG is rendered inline (not as a flat image) and that script tags are stripped.
  • Recall that SVG supports event-handler attributes that run JavaScript without any script tag.
  • Build an SVG whose element fires a handler on load.
  • Have that handler call the lab's solve function.

Full walkthrough (spoiler)

If a script tag is stripped but nothing else fires yet, reach for an event handler — open the steps.

Show the step-by-step solution
  1. Create a small SVG that uses an element with a load-time event-handler attribute (the sanitiser is not removing attributes).
  2. In that handler, call the page's solve function, window.seLabSolve('SE_LAB_XSS_SVG_2026').
  3. Upload it as your avatar. The sanitiser strips the script tag it looks for but leaves the handler intact.
  4. When the SVG renders, the handler runs and the lab marks you solved.

Why it works

The sanitiser enumerates one dangerous pattern — the script tag — and assumes that is the whole threat. SVG renders as live XML with many execution sinks (event handlers, and more). Anything the blocklist did not name survives, so a handler attribute runs exactly as script would.

Core principleDo not sanitise rich formats with a blocklist. Use a hardened allowlist sanitiser, or serve uploads as inert downloads from a separate origin.

Where this happens in the real world

SVG-based XSS is a recurring finding wherever user images are rendered inline — avatars, logos, document thumbnails. Regex or tag-strip sanitisers are repeatedly bypassed because the format has too many execution paths. XSS sits under Injection (A03) in the OWASP Top 10 (2021).

How to defend against it

  • Use a dedicated, allowlist-based SVG sanitiser (such as DOMPurify configured for SVG) rather than stripping tags yourself.
  • Serve user uploads from a separate origin with Content-Disposition: attachment so they download instead of rendering.
  • Set a strict Content-Security-Policy to limit what injected script can do.
  • Prefer rasterising uploads to PNG when you only need a picture, dropping all active content.
Mr Elite tip: When you see user-supplied SVG rendered inline, assume a tag-strip sanitiser can be bypassed. The real test is whether an event-handler attribute survives, not whether a script tag does.

Try it, then go further

Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.

❓ Frequently asked questions

Can an image really run JavaScript?
An SVG can. It is XML the browser renders live and supports event-handler attributes and other script sinks, so an inline SVG is an active document, not a flat picture.
Why isn't stripping script tags enough?
SVG has many ways to execute code beyond the script tag. A blocklist that removes only script tags leaves event handlers and other sinks intact.
How should I handle SVG uploads?
Sanitise with a hardened allowlist library, or serve uploads as attachments from a separate origin, or rasterise them to PNG so no active content survives.
Is a Content-Security-Policy enough on its own?
No, but it is a valuable backstop. Combine CSP with proper sanitisation or inert serving rather than relying on any one control.
⚡
Join free to earn XP for reading this article Track your progress, build streaks and compete on the leaderboard.
Join Free
Lokesh N. Singh aka Mr Elite
Lokesh N. Singh aka Mr Elite
Founder, Securityelites · AI Red Team Educator
Founder of Securityelites and creator of the SE-ARTCP credential. Working penetration tester focused on AI red team, prompt injection research, and LLM security education.
About Lokesh ->

Leave a Comment

Your email address will not be published. Required fields are marked *