v147 · Security · WebSockets Demo

WebSockets Demo

Illustrates which WebSocket connections Chrome 147 blocks versus allows, and what the LNA preflight looks like for connections from public pages to local network servers.

Chrome 147 adds LNA checks to WebSocket connections. The preflight is an HTTP GET request (before the WebSocket upgrade) with Access-Control-Request-Private-Network: true. The local server must respond with Access-Control-Allow-Private-Network: true.

try a WebSocket target

Classify a target URL and optionally invoke the WebSocket constructor to see the browser's readyState/error path from this page.

Choose a target, then classify or open a short WebSocket probe.

blocked vs allowed

Blocked (needs LNA opt-in)

  • Public page → ws://192.168.x.x:port
  • Public page → ws://10.x.x.x:port
  • Public page → ws://172.16-31.x.x:port
  • Public HTTPS page → ws://localhost:port
  • Public page → any .local mDNS host

Allowed (no opt-in needed)

  • Local page → local WebSocket server
  • localhost → localhost WebSocket
  • Public page → public WebSocket server
  • Local server responding with Access-Control-Allow-Private-Network: true

connection type matrix

Source context WebSocket target Chrome 147 result
https://public.example.com ws://192.168.1.100:8080 Preflight required → allowed if server opts in
https://public.example.com ws://localhost:3000 Preflight required → allowed if server opts in
https://public.example.com wss://api.public.example.com Allowed — both public
http://192.168.1.50 ws://192.168.1.100:8080 Allowed — both private
http://localhost:3000 ws://localhost:8080 Allowed — both localhost

server fix

// Local WebSocket server — Node.js with 'ws' package
const { WebSocketServer } = require('ws');

const wss = new WebSocketServer({ port: 8080 });

// The server must handle the LNA preflight GET request
// before the WebSocket upgrade
const http = require('http');
const server = http.createServer((req, res) => {
  if (req.headers['access-control-request-private-network']) {
    res.writeHead(200, {
      'Access-Control-Allow-Origin': req.headers.origin || '*',
      'Access-Control-Allow-Private-Network': 'true',
    });
    res.end();
    return;
  }
  res.writeHead(404);
  res.end();
});

// Attach WebSocket server to the same HTTP server
const wssWithHttp = new WebSocketServer({ server });
server.listen(8080);

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗