VYPR
Medium severity5.7GHSA Advisory· Published Jun 15, 2026· Updated Jun 15, 2026

@angular/service-worker: Request Credential & Cache Policy Stripping

CVE-2026-50184

Description

Angular Service Worker strips explicit credentials and cache settings from fetch requests, causing unintended credential exposure and cache persistence.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Angular Service Worker strips explicit `credentials` and `cache` settings from fetch requests, causing unintended credential exposure and cache persistence.

Vulnerability

In the @angular/service-worker package, the internal request reconstruction helper function strips explicit client-defined safety parameters (credentials and cache mode) from intercepted fetch requests, reverting them to browser defaults (credentials: 'same-origin' and default HTTP cache behavior). This affects all versions prior to the fix introduced in PR #68904 [1][2].

Exploitation

An attacker can exploit this vulnerability when the target application has an active Angular Service Worker, asset group patterns match the fetch request URLs, and the client-side code uses fetch() with explicit credentials: 'omit' or cache: 'no-store'. No additional attacker privileges are required; the service worker automatically strips the safety parameters upon interception [1][2].

Impact

Successful exploitation leads to two main consequences: (1) same-origin credentials (cookies, Authorization headers) are sent to endpoints that should not receive them, potentially enabling session hijacking; (2) private or non-cacheable resources are stored in the service worker cache, persisting after logout and allowing unauthorized access to sensitive data [1][2].

Mitigation

The fix is available in PR #68904, which preserves the explicit credentials and cache settings during request reconstruction [3]. Users should update @angular/service-worker to the patched version. As a temporary workaround, developers can avoid using credentials: 'omit' or cache: 'no-store' on fetch requests that match asset group patterns, or restructure asset groups to exclude such requests [1].

AI Insight generated on Jun 15, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

1
31399c217106

fix(service-worker): Preserves HTTP cache mode in asset group requests

https://github.com/angular/angularSkyZeroZxMay 24, 2026via body-scan-shorthand
3 files changed · +36 1
  • packages/service-worker/worker/src/assets.ts+9 1 modified
    @@ -501,12 +501,16 @@ export abstract class AssetGroup {
        * Create a new `Request` based on the specified URL and `RequestInit` options, preserving only
        * metadata that are known to be safe.
        *
    -   * Currently, headers, redirect policy, and an explicit `credentials: 'omit'` are preserved.
    +   * Currently, headers, redirect policy, an explicit `credentials: 'omit'`, and the HTTP cache
    +   * mode are preserved.
        *
        * NOTE:
        *   `credentials: 'same-origin'` and `credentials: 'include'` are intentionally not preserved.
        *   Forwarding `'include'` could leak cookies to cross-origin asset hosts, and forwarding
        *   `'same-origin'` matches the default `fetch()` behavior so there is nothing to preserve.
    +   *   Requests with `cache: 'only-if-cached'` and `mode !== 'same-origin'` are short-circuited
    +   *   earlier in `Driver.onFetch()` (they are a known Chrome DevTools quirk), so no special
    +   *   handling for that combination is needed here.
        * TODO(gkalpak):
        *   Investigate preserving more metadata. See, also, discussion on preserving `mode`:
        *   https://github.com/angular/angular/issues/41931#issuecomment-1227601347.
    @@ -521,6 +525,10 @@ export abstract class AssetGroup {
           init.credentials = 'omit';
         }
     
    +    if (options.cache !== undefined) {
    +      init.cache = options.cache;
    +    }
    +
         return this.adapter.newRequest(url, init);
       }
     
    
  • packages/service-worker/worker/test/happy_spec.ts+26 0 modified
    @@ -1667,6 +1667,18 @@ import {envIsSupported} from '../testing/utils';
             expect(bazReq.credentials).toBe('omit');
           });
     
    +      it(`passes 'cache' through to the server`, async () => {
    +        // Request a lazy-cached asset (so that it is fetched from the network) and provide an
    +        // explicit HTTP cache mode.
    +        const reqInit = {cache: 'no-store'};
    +        expect(await makeRequest(scope, '/baz.txt', undefined, reqInit)).toBe('this is baz');
    +
    +        // Verify that the explicit `cache` value was preserved (instead of being replaced by the
    +        // default `'default'`).
    +        const [bazReq] = server.getRequestsFor('/baz.txt');
    +        expect(bazReq.cache).toBe('no-store');
    +      });
    +
           describe('for redirect requests', () => {
             it('passes headers through to the server', async () => {
               // Request a redirected, lazy-cached asset (so that it is fetched from the network) and
    @@ -1721,6 +1733,20 @@ import {envIsSupported} from '../testing/utils';
               const [redirectReq] = server.getRequestsFor('/lazy/redirect-target.txt');
               expect(redirectReq.credentials).toBe('omit');
             });
    +
    +        it(`passes 'cache' through to the server`, async () => {
    +          // Request a redirected, lazy-cached asset (so that it is fetched from the network) and
    +          // provide an explicit HTTP cache mode.
    +          const reqInit = {cache: 'no-store'};
    +          expect(await makeRequest(scope, '/lazy/redirected.txt', undefined, reqInit)).toBe(
    +            'this was a redirect too',
    +          );
    +
    +          // Verify that the explicit `cache` value was preserved across the redirect
    +          // reconstruction (instead of being replaced by the default `'default'`).
    +          const [redirectReq] = server.getRequestsFor('/lazy/redirect-target.txt');
    +          expect(redirectReq.cache).toBe('no-store');
    +        });
           });
         });
     
    
  • packages/service-worker/worker/testing/fetch.ts+1 0 modified
    @@ -167,6 +167,7 @@ export class MockRequest extends MockBody implements Request {
         }
         return new MockRequest(this.url, {
           body: this._body,
    +      cache: this.cache,
           mode: this.mode,
           credentials: this.credentials,
           headers: this.headers,
    

Vulnerability mechanics

Root cause

"Missing forwarding of the HTTP cache mode (and credentials) during service-worker request reconstruction causes developer-specified safety parameters to be silently replaced with browser defaults."

Attack vector

An attacker exploits this by relying on the Angular Service Worker's asset-group interception. When a client-side fetch call uses `{ cache: 'no-store' }` to prevent caching of sensitive data, the service worker's reconstruction helper drops that directive, reverting to the browser default cache behavior. This causes private or non-cacheable resources to be stored in the service worker's cache storage, making them accessible or persistent post-logout. The same mechanism also strips `credentials: 'omit'`, causing the browser to attach same-origin cookies or Authorization headers to outbound requests where the developer explicitly intended them to be omitted, potentially leaking session credentials to unintended endpoints [patch_id=6084656].

Affected code

The vulnerability resides in `packages/service-worker/worker/src/assets.ts` within the `AssetGroup` class's request-reconstruction helper. The helper function was preserving `headers`, `redirect` policy, and an explicit `credentials: 'omit'`, but it did **not** forward the HTTP `cache` mode from the original request. The patch adds a check: `if (options.cache !== undefined) { init.cache = options.cache; }` so that an explicit cache mode (e.g. `'no-store'`) is carried through to the new `Request` object [patch_id=6084656].

What the fix does

The patch modifies the `AssetGroup` request-reconstruction helper in `assets.ts` to forward the original request's `cache` property when it is explicitly set. Previously only `headers`, `redirect` policy, and `credentials: 'omit'` were preserved; the `cache` mode was silently dropped, causing every reconstructed request to use the browser default (`'default'`). By adding `if (options.cache !== undefined) { init.cache = options.cache; }`, the fix ensures that a developer-specified cache mode such as `'no-store'` is honored, preventing unintended caching of sensitive responses [patch_id=6084656].

Preconditions

  • configThe target application uses @angular/service-worker with an active ngsw-worker.js registration.
  • configAn assetGroups pattern in ngsw-config.json matches the target dynamic routing endpoint.
  • authThe victim has an active authentication state (same-origin session cookies or auth headers).
  • inputThe application initiates a fetch call with explicit safety parameters such as { cache: 'no-store' } or { credentials: 'omit' } to a route matched by the service worker.

Generated on Jun 15, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.