Application Security

Service Worker Security Risks: The Persistent Threat in Your Browser

Service workers intercept network requests, cache content, and run in the background. When compromised, they become a persistent foothold in the browser.

Shadab Khan
Security Analyst
6 min read

Service workers are one of the most powerful features available to web applications. They sit between the browser and the network, intercepting every request the application makes. They can cache responses, modify requests, and run background tasks. This power is what makes Progressive Web Apps possible, but it is also what makes service worker compromise particularly dangerous.

A compromised service worker is a man-in-the-middle attack that persists across browser sessions, survives page reloads, and can modify every response the user sees. Understanding these risks is essential for any team building or deploying web applications that use service workers.

How Service Workers Create Risk

Request Interception

A service worker's fetch event handler intercepts every network request made by pages under its scope. This includes API calls, resource loads, and navigation requests. The service worker can modify these requests before they reach the server and modify the responses before they reach the page.

In normal operation, this is how service workers enable offline functionality and caching. In a compromise scenario, this means the attacker can read authentication tokens sent in request headers, modify API responses to display false information, redirect requests to attacker-controlled servers, and inject malicious scripts into HTML responses.

Cache Poisoning

Service workers manage the Cache API, which stores request-response pairs for offline use. A compromised service worker can populate the cache with malicious content. When the user goes offline or when the application reads from cache, it receives the attacker's content.

Cache poisoning through service workers is particularly insidious because the malicious content persists. Even if the network attack that delivered the compromised service worker is no longer active, the poisoned cache continues to serve malicious content.

Persistence

Service workers persist across browser sessions. Once registered, a service worker remains active until it is explicitly unregistered or replaced by an update. This gives an attacker persistent access to the origin's traffic without needing to maintain access to the server.

A compromised service worker can also interfere with its own replacement. If the attacker's service worker intercepts requests for the updated service worker script, it can serve the old (compromised) version, preventing the legitimate update from installing.

Background Execution

Service workers can execute code in the background through the Push API and Background Sync API. This means a compromised service worker can perform actions when the user is not actively using the application: sending exfiltrated data, receiving commands from a C2 server, or periodically checking for updates from the attacker.

Attack Scenarios

XSS to Service Worker Registration

The most common attack path is through a cross-site scripting vulnerability. If an attacker can execute JavaScript on your origin, they can register a malicious service worker. The XSS might be a fleeting vulnerability that is quickly patched, but the service worker it registered persists long after the XSS is fixed.

This is why service worker registration is a particularly high-impact consequence of XSS. A traditional XSS attack ends when the user closes the page. An XSS that registers a service worker gives the attacker persistent control.

CDN Compromise

If your service worker script is served through a CDN and the CDN is compromised, the attacker can serve a modified service worker to all users. The modified service worker installs normally and gives the attacker control over all subsequent traffic.

Supply Chain Compromise

If your service worker imports scripts from third-party origins using importScripts(), a compromise of any of those third-party scripts compromises your service worker. The imported script runs with the same privileges as your service worker.

Mitigations

HTTPS Enforcement

Service workers require HTTPS (except on localhost). This prevents network-level man-in-the-middle attacks from registering malicious service workers. However, HTTPS does not protect against application-level attacks like XSS or CDN compromise.

Strict Content Security Policy

Implement a CSP that restricts script sources. If only scripts from your own origin are allowed, an XSS vulnerability cannot load a malicious service worker from an external source.

Content-Security-Policy: script-src 'self'

Service Worker Scope Limitation

Register service workers with the narrowest possible scope. A service worker scoped to /app/ cannot intercept requests to /admin/ or other paths outside its scope.

Subresource Integrity

If your service worker uses importScripts(), consider hosting those scripts on your own origin rather than loading them from third parties. If you must load from third parties, implement verification of the script content.

Cache-Control Headers

Configure your server to return appropriate Cache-Control headers for the service worker script file. The browser checks for updates to the service worker on each navigation, but caching headers affect how aggressively it checks.

Set Cache-Control: no-cache or a short max-age for the service worker script to ensure updates propagate quickly.

Monitor Service Worker Registration

Implement monitoring that detects unexpected service worker registrations. If your application should only have one service worker at a specific scope, alert on registrations at other scopes.

Clear Site Data Header

The Clear-Site-Data response header can unregister service workers as a remediation step. If you detect a compromise, returning this header from your server removes all cached data and service worker registrations for your origin:

Clear-Site-Data: "cache", "cookies", "storage"

Service Worker Update Mechanism

Implement a mechanism for your application to verify the integrity of its service worker. The application can fetch the service worker script directly and compare its hash against an expected value. If the hashes do not match, alert the user and trigger an update.

Detection

Anomalous Network Patterns

Monitor for unusual network requests originating from service workers: connections to unexpected domains, data uploads that do not match your application's behavior, or request patterns that differ from normal service worker caching.

Script Integrity Monitoring

Periodically verify the content of your service worker script as served by your CDN or server. Compare it against the expected content from your build system. Any discrepancy indicates a potential compromise.

User Reports

Users who notice unexpected behavior, modified content, or redirects may be experiencing a compromised service worker. Have a process for investigating these reports and include service worker inspection in your investigation procedures.

How Safeguard.sh Helps

Safeguard.sh monitors the dependencies and components in your web applications, including the libraries and scripts that your service workers rely on. It identifies vulnerable dependencies before they reach production, tracks the provenance of third-party scripts, and generates SBOMs that catalog every component in your web application supply chain. When a dependency used by your service worker has a security issue, Safeguard.sh ensures you know about it before it becomes an attack vector.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.