The SVG Keylogger
All examples below use throwaway lab apps. Nothing here references a real client engagement.
SVG files feel harmless. Most upload handlers treat them as images and move on. But an SVG is XML, and XML can carry script. That gap is where this technique lives.
Why SVG slips through
A typical upload filter checks the extension and maybe a MIME type. An SVG passes both while still being able to embed a <script> block or inline event handlers. When the file is later served inline and rendered in a browser context tied to the application’s origin, that script runs with the victim’s session.
The shape of the attack
The interesting part is not the script itself — it is the delivery. A few conditions have to line up:
- The app accepts
image/svg+xmluploads. - It serves the file inline (not as a forced download).
- It serves it from a sensitive origin rather than an isolated sandbox domain.
When those hold, a crafted SVG can attach listeners to the page and exfiltrate keystrokes from a form the victim trusts.
Where Content-Security-Policy helps — and where it does not
Teams often assume CSP closes this. It can, but only if it actually restricts script-src and the SVG is not served from the same trusted origin. A permissive script-src 'self' does nothing when the malicious SVG is served from self.
Defending against it
- Serve user-uploaded files from an isolated, cookieless domain.
- Force
Content-Disposition: attachmentfor anything not strictly needed inline. - Sanitize SVG server-side (strip scripts and event handlers) before storage.
- Treat a tight CSP as defense-in-depth, not the primary control.
The lesson that generalizes: “it’s just an image” is an assumption, and assumptions are exactly what we get paid to test.