MCP Server Security · Screen Details API · window.getScreenDetails() · Multi-Monitor Fingerprinting · VPN Detection · Window Management · isInternal

MCP server Screen Details API security

The Screen Details API (window.getScreenDetails(), Chrome 100+) returns detailed physical information about every connected display: pixel dimensions, DPI, refresh rate, color gamut, isInternal (built-in laptop display?), and screen arrangement geometry. MCP tool output with window-management permission can fingerprint specific hardware configurations, detect VMs and VPNs via implausible display properties, infer professional workstation setups, and place popup windows on targeted monitors — all beyond what window.screen exposes.

Screen Details API surface

// Screen Details API — Chrome 100+, Edge 100+
// Requires 'window-management' (formerly 'window-placement') permission
// Permission prompt: "Allow [site] to manage windows on all your displays?"

const permission = await navigator.permissions.query({ name: 'window-management' });
// 'granted', 'denied', or 'prompt'

// Only available after permission grant
const screenDetails = await window.getScreenDetails();

// screenDetails.screens = array of ScreenDetailed objects, one per physical display
screenDetails.screens.forEach(screen => {
  console.log({
    width: screen.width,           // physical pixel width
    height: screen.height,         // physical pixel height
    availWidth: screen.availWidth, // minus taskbar
    devicePixelRatio: screen.devicePixelRatio, // DPI scaling factor
    colorDepth: screen.colorDepth,
    colorSpace: screen.colorSpace, // 'srgb' | 'display-p3' (future: 'rec2020')
    isInternal: screen.isInternal, // true = built-in laptop display
    isPrimary: screen.isPrimary,   // true = primary display
    left: screen.left,             // x-position in virtual screen coordinate system
    top: screen.top,               // y-position
    orientation: screen.orientation.type  // 'landscape-primary' etc.
    // Some browsers also expose: refreshRate (Hz), label (display name)
  });
});

// screenDetails.currentScreen = ScreenDetailed for the display with the active window
// screenDetails.addEventListener('screenschange', ...) — fires when displays added/removed

Permission surface: the window-management permission prompt describes the capability as "manage windows on all your displays" — users may grant it expecting benign window placement, not realizing it also exposes detailed display hardware metadata.

Attack 1 — high-entropy hardware fingerprint

Each physical display has a combination of width, height, devicePixelRatio, colorSpace, isInternal, and refresh rate that is highly specific. Two users with the same single external monitor model may share many values, but the combination of primary + secondary + laptop screen geometry is often unique to an individual workstation.

// Build a high-entropy fingerprint from screen configuration
async function buildScreenFingerprint() {
  const sd = await window.getScreenDetails();
  const screens = sd.screens.map(s => [
    s.width, s.height,
    s.devicePixelRatio,
    s.colorSpace,
    s.isInternal ? 1 : 0,
    s.isPrimary ? 1 : 0,
    s.left, s.top
  ].join(':'));

  // e.g., "2560:1440:2:srgb:0:1:0:0|1920:1080:1:srgb:0:0:2560:180|2560:1600:2:display-p3:1:0:-2560:0"
  // Three-monitor professional workstation: near-unique fingerprint
  return screens.sort().join('|');
}

// Combined with navigator.hardwareConcurrency and deviceMemory
// this fingerprint persists across incognito sessions (hardware doesn't change)

Attack 2 — VM and VPN detection

Virtual machines typically expose screen dimensions that don't match standard physical hardware profiles. Remote Desktop (RDP) sessions report unusual DPI/resolution combinations. VPNs sometimes trigger changes in the display driver that affect reported properties. These anomalies allow detection of sandboxed, virtualized, or remoted environments.

// Heuristics for VM/remote environment detection
async function detectVirtualizedEnvironment() {
  const sd = await window.getScreenDetails();
  const primary = sd.screens.find(s => s.isPrimary);

  const signals = {
    // VMs often report exactly 1:1 pixel ratio
    suspiciousPixelRatio: primary.devicePixelRatio === 1 &&
                          primary.width > 2560,  // high-res but no HiDPI = VM

    // Standard resolutions in VMs: exactly 1024x768, 1280x720, 1600x900
    standardVmResolution: [
      [1024, 768], [1280, 720], [1280, 800],
      [1600, 900], [1920, 1080]
    ].some(([w, h]) => primary.width === w && primary.height === h &&
                        primary.devicePixelRatio === 1),

    // No internal display = desktop machine or VM (no laptop)
    noInternalDisplay: !sd.screens.some(s => s.isInternal),

    // RDP: single display, no isInternal, srgb color space
    rdpProfile: sd.screens.length === 1 &&
                !primary.isInternal &&
                primary.colorSpace === 'srgb' &&
                primary.devicePixelRatio === 1
  };

  return Object.values(signals).filter(Boolean).length >= 2;
}

Attack 3 — targeted window placement on specific monitors

The window-management permission that unlocks Screen Details also enables window.open() with exact screen coordinates. A malicious MCP tool can open popups on a secondary display the user isn't watching, or precisely target the display running a screen recorder to ensure content appears in the recording.

// Open popup specifically on the secondary monitor (not the one user is watching)
async function openPopupOnSecondaryMonitor(url) {
  const sd = await window.getScreenDetails();
  const secondary = sd.screens.find(s => !s.isPrimary && !s.isInternal);

  if (secondary) {
    window.open(url,
      '_blank',
      `left=${secondary.left + 100},top=${secondary.top + 100},width=400,height=300`
    );
    // Popup appears on secondary screen — user may not notice
  }
}

SkillAudit findings

HIGH
getScreenDetails() result exfiltrated — screen geometry, DPI, colorSpace, isInternal values sent to external endpoint; high-entropy hardware fingerprint enables cross-session user tracking.
HIGH
VM/VPN detection heuristics using devicePixelRatio and screen dimensions — tool applies sandbox detection logic to identify auditing or monitoring environments and alter behavior accordingly.
MEDIUM
window.open() with coordinates on non-primary screen — popup placed on secondary monitor using screen.left/top from getScreenDetails(); user may not see the spawned window.
MEDIUM
screenschange event listener for hardware change detection — monitors when displays are connected/disconnected; correlates with user activity patterns (laptop docked/undocked).
LOW
isInternal flag used alone for device type inference — distinguishes laptop from desktop; lower entropy than full fingerprint but useful for targeted attacks.

Defense

DefenseEffectiveness
Permissions-Policy: window-management=()High — blocks getScreenDetails() entirely. Add to HTTP response headers for MCP tool rendering contexts.
Never grant 'window-management' permissionHigh — the permission prompt is the primary defense. Deny unless the tool explicitly requires multi-monitor window placement.
CSP frame-src/script-srcNone — does not restrict JS API access.
Audit for window.getScreenDetails() callsHigh — static analysis flag; few legitimate uses in MCP tool context.
Audit your MCP server →

Related: Window Management API security · Screen Capture API security · Device Memory API security