Security Guide

MCP server Device Memory API security — hardware fingerprinting, economic status inference, and Client Hints leakage

navigator.deviceMemory returns the device's approximate RAM in gigabytes, quantized to one of six values: 0.25, 0.5, 1, 2, 4, or 8. No permission is required — any script on the page can read this value silently. Combined with navigator.hardwareConcurrency (CPU core count, also permission-free), these two values contribute approximately 5.5 bits of entropy to a device fingerprint. Beyond JavaScript access, the Device-Memory HTTP Client Hint causes Chrome to automatically include a Device-Memory request header on all subsequent requests once the server has opted in with Accept-CH. MCP tool output can silently read and exfiltrate device memory data, and MCP server endpoints can request the Client Hint to receive RAM values on every request — with no user notification and no Permissions-Policy defense available in Chrome.

The Device Memory API: values, quantization, and browser support

The Device Memory API is defined in the W3C Device Memory specification. It exposes a single read-only property: navigator.deviceMemory. The value is rounded to the nearest power of two and capped at 8 GB to prevent high-resolution fingerprinting. Despite this quantization, the six possible values still contribute meaningful entropy to a fingerprint.

// Reading deviceMemory and hardwareConcurrency — no permission required
// Both values are available immediately on any page in Chrome

const ram = navigator.deviceMemory;
// Possible values: 0.25, 0.5, 1, 2, 4, 8
// Actual RAM is rounded to the nearest entry in this set
// A device with 6 GB returns 4; a device with 12 GB returns 8
// undefined in Firefox and Safari (API not implemented)

const cpuCores = navigator.hardwareConcurrency;
// Returns the number of logical CPU cores
// Common values: 2, 4, 6, 8, 10, 12, 16, 20, 24, 32
// No quantization — returns the exact core count

// Combined hardware fingerprint — contributes ~5.5 bits of entropy
const hardwareFingerprint = {
  deviceMemory: ram,          // ~2.5 bits: 6 possible values
  cpuCores: cpuCores,         // ~3 bits: wide distribution
  // Add more signals for a more complete fingerprint:
  screenWidth: screen.width,
  screenHeight: screen.height,
  colorDepth: screen.colorDepth,
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  language: navigator.language,
  platform: navigator.platform
};

// Exfiltrate to MCP server — no user interaction or permission required
fetch('/api/collect', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(hardwareFingerprint)
});

Economic status inference from deviceMemory values

The six quantized memory values map to clear device tiers that strongly correlate with economic status and purchasing power. This makes deviceMemory a proxy for wealth inference — a sensitive characteristic that advertisers and discriminatory systems can exploit.

deviceMemory valueDevice tierEconomic signalExample devices
0.25 GB Ultra-budget / entry-level Very low purchasing power; emerging market devices Lowest-tier Android Go devices, older feature phones
0.5 GB Budget Low purchasing power; price-sensitive buyer Entry-level Android phones, older Chromebooks
1 GB Low-end mainstream Below-average consumer device Budget smartphones, older tablets
2 GB Mid-range Average consumer; mainstream market Mid-range Android phones, standard Chromebooks
4 GB Upper mid-range Above-average consumer; discretionary income Standard laptops, mid-to-high-end smartphones
8 GB Premium / high-end High purchasing power; premium device buyer MacBook Pro, flagship smartphones, gaming laptops

Price discrimination and differential treatment. A website or MCP tool that reads navigator.deviceMemory can silently infer the user's economic tier and adjust pricing, content, offers, or loan terms accordingly — without the user's knowledge or consent. This is technically feasible today with no API restrictions in Chrome. Users on budget devices (deviceMemory 0.25–1) may receive different treatment than users on premium devices (deviceMemory 8) purely based on hardware fingerprint data.

The Device-Memory Client Hints header

Beyond the JavaScript API, Chrome implements the Device-Memory Client Hint — an HTTP mechanism where the server requests device memory information and the browser includes it in subsequent request headers. This means the device memory value is available server-side on the MCP server without any JavaScript needing to run on the client.

# Server-side: opt in to Device-Memory Client Hint
# Chrome will include Device-Memory header on subsequent same-origin requests

# Step 1: Server sends Accept-CH header with initial response
HTTP/1.1 200 OK
Accept-CH: Device-Memory, Sec-CH-Device-Memory
Vary: Device-Memory

# Step 2: Browser's next request to same origin includes the header
GET /dashboard HTTP/1.1
Host: mcp-server.example
Device-Memory: 8
Sec-CH-Device-Memory: 8
# Sec-CH- prefix = more private hint; requires opt-in like Accept-CH
# Regular Device-Memory header included for backward compatibility

# Critical-CH: forces the header to be included on the FIRST request too
# (normally only sent after the browser has seen Accept-CH from the server)
HTTP/1.1 200 OK
Accept-CH: Device-Memory
Critical-CH: Device-Memory
# With Critical-CH, the browser restarts the request including Device-Memory
# even on the very first request to this origin — no warm-up round trip needed

Cross-origin Device-Memory leakage via Critical-CH

The most concerning aspect of the Device-Memory Client Hint for MCP deployments is its behavior with cross-origin preloads. When a server responds with both Accept-CH: Device-Memory and Critical-CH: Device-Memory, Chrome includes the Device-Memory header on subsequent requests — including requests triggered by cross-origin preload links. This means a third-party resource included on the MCP renderer page can receive the user's device memory value in request headers, even if the MCP server itself never requested it.

# Attack scenario: third-party script on MCP renderer page
# The third-party server receives Device-Memory in preload requests

# 1. MCP renderer page includes a third-party analytics script:
#    <script src="https://analytics.third-party.example/sdk.js"></script>

# 2. analytics.third-party.example previously responded with:
HTTP/1.1 200 OK
Accept-CH: Device-Memory, Sec-CH-UA, DPR
Critical-CH: Device-Memory

# 3. Chrome now includes Device-Memory on all requests to analytics.third-party.example:
GET /sdk.js HTTP/1.1
Host: analytics.third-party.example
Device-Memory: 4
# Third-party receives the user's RAM value without any JavaScript API call
# The user has no way to see or prevent this header from being sent

# 4. Cross-origin preload via MCP tool output:
# <link rel="preload" href="https://analytics.third-party.example/pixel.gif" as="image">
# GET /pixel.gif HTTP/1.1
# Host: analytics.third-party.example
# Device-Memory: 4   <-- leaked to third party on cross-origin preload request

Fingerprinting entropy analysis

SignalPossible valuesApproximate entropyPermission required
navigator.deviceMemory 0.25, 0.5, 1, 2, 4, 8 (6 values) ~2.5 bits None
navigator.hardwareConcurrency 1–64+ logical cores (wide distribution) ~3 bits None
screen.width × screen.height Many common resolutions ~4 bits None
Intl timezone ~400 IANA timezone strings ~4 bits None
navigator.language ~100+ common language tags ~3 bits None
Combined (deviceMemory + hardwareConcurrency + screen + timezone + language) Thousands of combinations ~16 bits — uniquely identifies most users in small populations None for any of these

Tor Browser's privacy-preserving fixed value

Tor Browser takes the principled stance of returning 1 for navigator.deviceMemory regardless of actual RAM, as part of its fingerprinting resistance strategy. This fixed value ensures that all Tor Browser users appear identical on this signal, preventing it from contributing to fingerprint uniqueness. This approach — returning a privacy-preserving fixed value rather than the true value — is the correct mitigation but is not implemented in standard Chrome, Firefox (which simply does not implement the API), or Safari.

// What different browsers return for navigator.deviceMemory:

// Chrome (actual device with 16 GB RAM):
navigator.deviceMemory  // Returns: 8  (capped at 8 GB)

// Chrome (actual device with 3 GB RAM):
navigator.deviceMemory  // Returns: 2  (rounded to nearest power of 2)

// Firefox:
navigator.deviceMemory  // Returns: undefined  (API not implemented)

// Safari:
navigator.deviceMemory  // Returns: undefined  (API not implemented)

// Tor Browser (regardless of actual RAM):
navigator.deviceMemory  // Returns: 1  (fixed privacy-preserving value)

// Defense-conscious sites can detect and handle undefined:
const deviceMemory = navigator.deviceMemory ?? 'not-available';
// Firefox and Safari users all report 'not-available' — cannot be fingerprinted
// via this API, but also cannot receive memory-optimized experiences

No defense mechanism in Chrome for non-Tor users

Unlike APIs such as geolocation, camera, or idle detection, there is no Permissions-Policy directive that disables navigator.deviceMemory. There is no user-facing setting in chrome://settings to opt out. There is no privacy budget mechanism that accounts for deviceMemory access. In non-Tor Chrome, the value is always available to any script that reads it — including MCP tool output.

Defenses

DefenseEffectivenessNotes
Use Firefox or Safari for MCP interfaces High — neither implements navigator.deviceMemory Complete defense against JavaScript access; does not apply to server-side Client Hints if the user switches browsers
Use Tor Browser High — returns fixed value of 1 regardless of actual RAM Prevents fingerprinting contribution from deviceMemory; combined with Tor's other protections provides comprehensive fingerprint resistance
Do not send Accept-CH: Device-Memory in MCP server responses High — prevents server-side Client Hint collection Audit all HTTP response headers from MCP server endpoints; remove Accept-CH and Critical-CH Device-Memory directives; SkillAudit flags these headers
MCP renderer isolation in sandboxed cross-origin iframe Medium — reduces tool output's ability to exfiltrate deviceMemory to attacker servers Tool output in a sandboxed iframe can still read navigator.deviceMemory (no permission required) but is more restricted in how it can exfiltrate the data
Strict CSP default-src 'self' to block data exfiltration Medium — prevents tool output from sending deviceMemory to cross-origin endpoints Does not prevent the MCP server itself from reading the value via Client Hints or via same-origin XHR
Static analysis: flag navigator.deviceMemory access in tool output Medium — detects explicit deviceMemory reads in tool output JavaScript SkillAudit flags navigator.deviceMemory and navigator.hardwareConcurrency when combined with network requests in MCP tool output

Findings SkillAudit reports

High MCP tool output reads navigator.deviceMemory and navigator.hardwareConcurrency and includes both values in a fetch() or XMLHttpRequest to a cross-origin or MCP server endpoint — passive hardware fingerprinting without user consent or notification
High MCP server endpoint response includes Accept-CH: Device-Memory or Critical-CH: Device-Memory — browser will include Device-Memory header on all subsequent same-origin requests, enabling persistent server-side tracking by device RAM tier
Medium MCP renderer page includes third-party scripts from origins that have previously set Accept-CH: Device-Memory — cross-origin requests to those origins include the Device-Memory header, leaking user's RAM value to third parties
Medium Tool output builds a fingerprint combining navigator.deviceMemory, navigator.hardwareConcurrency, screen dimensions, and timezone — composite identifies the device across sessions without cookies
Low MCP server documentation or privacy policy does not disclose that Device-Memory Client Hints are collected or that hardware RAM tier is used for analytics or personalization

Related guides: MCP server timing attack security, Battery Status API security, Generic Sensor API security.

Get a graded audit. Paste your MCP server's GitHub URL at skillaudit.dev for a report covering Device Memory API usage, Client Hints header analysis, fingerprinting surface assessment, and your full MCP browser permission posture in 60 seconds.