v147 · Security · Navigate Demo
Navigate Demo
Illustrates the attack vector that Chrome 147's LNA restriction closes, and the exact URL categories where WindowClient.navigate() is now blocked from a public service worker.
WindowClient.navigate() is only callable from inside a service worker. The restriction applies when the service worker was registered from a public origin and the target URL is a private network or loopback address.
safe navigate decision tester
Enter the service worker origin and target URL. The tester performs the same network-tier decision without navigating this tab away.
blocked attack scenario
-
1
User visits
https://compromised.example.com— registers a service worker - 2 Service worker listens for a trigger (push notification, timer, fetch event)
-
3
Service worker calls
client.navigate('http://192.168.1.1/admin')for any open window it controls - ✗ Chrome 147 blocks this. The navigate() promise rejects — the user's window is not redirected to the local network URL.
navigate() URL rules
| SW origin | navigate() target | Chrome 147 |
|---|---|---|
| https://public.example.com/sw.js | http://192.168.1.1/admin | Blocked — private IP |
| https://public.example.com/sw.js | http://localhost:8080 | Blocked — loopback |
| https://public.example.com/sw.js | http://10.0.0.1 | Blocked — private IP |
| https://public.example.com/sw.js | https://public.example.com/page | Allowed — same origin, public |
| https://public.example.com/sw.js | https://other.public.com/ | Allowed — both public |
| http://192.168.1.50/sw.js | http://192.168.1.100/ | Allowed — private to private |
code
// service-worker.js
self.addEventListener('message', async event => {
if (event.data.type !== 'navigate') return;
const clients = await self.clients.matchAll({ type: 'window' });
for (const client of clients) {
try {
// Chrome 147: throws if SW is public and target is private
const navigated = await client.navigate(event.data.url);
if (navigated === null) {
// null = URL was same-origin but out of scope
console.log('Navigate returned null: out of scope');
}
} catch (err) {
// LNA block or invalid URL
console.error('navigate() failed:', err.message);
}
}
});
see also
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗