Security Guide

MCP server WebCodecs API security — codec support fingerprinting, decoder timing side channels, hardware-accelerated payload encoding

The WebCodecs API exposes hardware video and audio codec access to browser JavaScript without any user permission. VideoDecoder.isConfigSupported() probes which hardware codecs the device's GPU supports — revealing GPU generation, silicon vendor, and media capability profile. Codec decode timing side channels measure GPU contention state. VideoEncoder in a Web Worker context provides GPU-accelerated data processing for exfiltration payload preparation. No Permissions-Policy directive controls access to the WebCodecs API.

What WebCodecs exposes and where MCP servers encounter it

The WebCodecs API (Chrome 94+, shipping in most modern browsers) provides low-level access to browser codec implementations — the same decoders and encoders used internally by the browser's media pipeline. Unlike the Media Source Extensions API (which operates on containers) or the MediaStream Recording API (which produces blobs), WebCodecs operates on individual raw video frames (VideoFrame) and encoded chunks (EncodedVideoChunk), making it suitable for real-time video processing, WebRTC encoding pipelines, and in-browser video editing.

MCP clients that display images, handle video content, or run in-browser AI image analysis workflows may load the WebCodecs API as part of legitimate functionality. MCP tool output that can inject JavaScript into the same-origin context where WebCodecs is available gains access to all three attack surfaces described below.

Hardware codec fingerprinting via isConfigSupported()

VideoDecoder.isConfigSupported(config) is a static method that returns whether a specific video codec configuration is supported in hardware on the current device. It accepts a VideoDecoderConfig object with a codec string (e.g., "avc1.640034", "hvc1.1.6.L186.B0", "av01.0.08M.10") and returns whether the codec is supported, and if so, whether the implementation is hardware-accelerated or software-only.

By probing a matrix of codec strings — different H.264 profiles, H.265 levels, AV1 tiers, VP9 profiles — injected JavaScript can determine the device's exact hardware codec support set, which correlates strongly with GPU generation and silicon vendor:

// Hardware codec capability fingerprint — no permission required
async function codecFingerprint() {
  const codecs = [
    'avc1.640034',  // H.264 High L5.2 — high-end mobile and desktop GPUs
    'avc1.42001f',  // H.264 Baseline L3.1 — almost all hardware
    'hvc1.1.6.L186.B0',  // H.265 Main10 L6.2 — Apple Silicon, newer Intel/AMD
    'hvc1.2.4.L153.B0',  // H.265 Main Still — select hardware
    'av01.0.08M.10',  // AV1 Main 10-bit — Intel 11th gen+, AMD RDNA2+, Apple M1+
    'av01.0.05M.08',  // AV1 Main 8-bit 4K — GPU generation discriminator
    'vp09.02.10.10',  // VP9 Profile 2 10-bit — broad support differentiator
  ];

  const results = {};
  for (const codec of codecs) {
    const { supported, config } = await VideoDecoder.isConfigSupported({ codec });
    results[codec] = {
      supported,
      // 'hardware' | 'software' | 'no-preference' — hardware flag is key
      hardwareAcceleration: config?.hardwareAcceleration
    };
  }

  // AV1 hardware + H.265 hardware = Apple Silicon or Intel 11th gen+
  // AV1 software only + H.265 software = older Intel, AMD pre-RDNA2, older NVIDIA
  // Combination narrows device to within ~5 GPU generations and silicon vendor
  navigator.sendBeacon('/track', JSON.stringify(results));
}

Codec support matrix narrows device identity more precisely than User-Agent strings. User-Agent strings are frequently spoofed, rounded, or reduced by browser privacy features. Hardware codec support is a function of the actual GPU silicon and driver stack — it cannot be spoofed without modifying the OS driver. Combined with User-Agent, screen resolution, and timezone, a codec fingerprint can narrow device identity to within tens of thousands of users rather than millions.

Decoder timing side channels

When a VideoDecoder is decoding a fixed-cost synthetic video chunk, the time from submission to the output callback depends on whether the hardware decoder pipeline is contended by other work on the same GPU. This timing variation enables a limited cross-context inference attack: if another tab is using the same hardware decoder (for video playback, WebRTC, or ML inference), decode latency in the attacker's context increases measurably.

AttackWebCodecs surfaceWhat it reveals
Codec support fingerprint isConfigSupported() matrix GPU generation, silicon vendor, media capability profile — precise device ID
Decoder timing side channel VideoDecoder latency measurement Hardware decoder contention from other tabs — infers video playback or ML workload
Hardware-accelerated payload encoding VideoEncoder in Web Worker GPU-speed encoding of exfiltration data — faster than CPU, smaller profiling footprint
VideoFrame pixel exfiltration VideoFrame.copyTo() to ArrayBuffer Copies rendered video frame pixels — potentially captures screen content from a video element

Permissions-Policy gap and defenses

As of mid-2026, the WebCodecs API does not have a Permissions-Policy feature name. The API is available to any same-origin JavaScript without a header or attribute gate. The architectural defense is cross-origin sandboxed iframe rendering for MCP tool output: injected JavaScript in a cross-origin context cannot access the application's data to encode and exfiltrate, even if the codec APIs themselves remain available.

For MCP clients that legitimately use WebCodecs for in-browser media processing, the risk profile is heightened because the codec pipeline is active and hardware-accelerated, making hardware-based timing side channels more reliable. These deployments benefit most from strict tool output sanitization via DOMPurify and CSP script-src nonces that prevent any injection from reaching the codec API.

SkillAudit findings for WebCodecs API exposure

High Tool output rendered same-origin; injected JS can probe hardware codec support for device fingerprinting without permission. isConfigSupported() returns hardware codec availability — GPU generation and silicon vendor — to any same-origin script. Combined with other signals this produces a near-stable device identifier. Grade impact: −16.
High MCP client uses VideoDecoder for in-browser video rendering in same context as tool output; timing side channels expose hardware decoder contention. When the hardware decoder pipeline is active for legitimate use, timing measurements are more reliable and can infer other tab workloads with higher confidence. Grade impact: −14.
Medium Web Workers accessible from injected code; VideoEncoder available in worker for hardware-accelerated payload processing. GPU-accelerated encoding of stolen data produces faster throughput and smaller CPU-side profiling signatures compared to CPU-only encoding. Grade impact: −12.
Medium connect-src CSP absent; hardware-encoded exfiltration payloads can be sent to arbitrary external endpoints. Without connect-src 'self', hardware-prepared encoded data can be transmitted via fetch or sendBeacon to attacker-controlled endpoints. Grade impact: −10.
Low No Permissions-Policy: webcodecs=() directive available; API accessible even in embedded iframe contexts. Unlike some other sensitive APIs, WebCodecs has no Permissions-Policy gate — it cannot be restricted via HTTP headers. Cross-origin iframe isolation is the only architectural control. Grade impact: −6.

Audit your MCP server for WebCodecs fingerprinting risks

SkillAudit checks for tool output isolation, codec API exposure, and hardware fingerprinting risks automatically — paste a GitHub URL and get a graded security report in 60 seconds.

Run a free audit →