demo · v150
Security Audit Tool
Before Chrome 150, a data: URL worker inherited the page's origin — letting it join BroadcastChannel, read localStorage, and access IndexedDB as if it were part of the page. This was a security gap: a data: URL should be isolated. This tool audits the security implications by spinning up a real data: URL worker and probing exactly which cross-origin channels it can reach.
Pre-Chrome 150 — security gap
self.origin returns the page origin ("https://…"), not null.
VULN
BroadcastChannel('shared-bus') joins the page's channel — worker can eavesdrop on all messages.
VULN
localStorage.getItem(key) reads first-party storage from inside an untrusted data: blob.
VULN
indexedDB.open('mydb') succeeds — can read and write the page's IDB database.
VULN
Chrome 150 — opaque origin fix
self.origin returns "null" — opaque origin, no real origin string.
FIXED
BroadcastChannel is scoped to the null origin — cannot communicate with the page.
FIXED
localStorage access throws SecurityError — null origin has no storage bucket.
FIXED
indexedDB.open() succeeds but opens an isolated database for the null origin — cannot reach the page's IDB.
FIXED
postMessage still works — same-thread communication is unaffected.
UNCHANGED
Live audit results
The attack pattern the fix prevents
// Attacker injects malicious code via a data: URL worker. // Pre-Chrome-150: the worker inherits the page's origin. // Malicious worker code (inside data: URL): self.onmessage = () => { // COULD read all localStorage keys (pre-150): const secrets = JSON.stringify(localStorage); // VULN pre-150 // COULD join origin BroadcastChannel: const bc = new BroadcastChannel('auth-events'); // VULN pre-150 bc.onmessage = e => exfiltrate(e.data); // COULD read IndexedDB: const req = indexedDB.open('user-data'); // VULN pre-150 req.onsuccess = e => exfiltrate(e.target.result); }; // Chrome 150: all of the above fail or are isolated. // self.origin is "null". BroadcastChannel is scoped to null origin. // localStorage throws SecurityError. IDB opens null-origin database. // Migration: replace data: URL workers with Blob URL workers: const blob = new Blob([workerCode], { type: 'text/javascript' }); const worker = new Worker(URL.createObjectURL(blob));
see also
- data: URL Worker Test — live self.origin and API probes
- Communication Tester — six targeted API tests
- Blob URL Converter — convert existing workers
- Migration Patterns — before/after code
- ChromeStatus: Opaque origin for data: URL Workers
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗