Summary
Undici's cache interceptor incorrectly handles certain malformed Cache-Control private directives, allowing responses intended for a single user to be stored in a shared cache and served to other callers. This can expose private response bodies and headers, including Set-Cookie, and in some cases trigger an uncaught TypeError that may terminate the process.
The vulnerability becomes risky when applications rely on undici's cache interceptor in shared mode (including the default configuration) and consume responses with degenerate or mixed private Cache-Control directives from upstream services.
Undici's cache interceptor incorrectly handles certain malformed Cache-Control private directives, allowing responses intended for a single user to be stored in a shared cache and served to other callers. This can expose private response bodies and headers, including Set-Cookie, and in some cases trigger an uncaught TypeError that may terminate the process.
The vulnerability becomes risky when applications rely on undici's cache interceptor in shared mode (including the default configuration) and consume responses with degenerate or mixed private Cache-Control directives from upstream services.
Affected context
This vulnerability occurs in Node.js applications that use undici's cache interceptor in shared mode, including default setups where multiple callers share the same cache. It manifests when upstream HTTP responses carry malformed or atypical Cache-Control headers involving qualified and unqualified private directives. In those conditions, the cache logic can incorrectly treat private responses as publicly cacheable, or the header parsing can throw an uncaught TypeError that propagates back to the application. The issue is specific to the interceptor's shared caching behavior and the parser's error handling, and does not affect clients that avoid the cache interceptor entirely.
This vulnerability occurs in Node.js applications that use undici's cache interceptor in shared mode, including default setups where multiple callers share the same cache. It manifests when upstream HTTP responses carry malformed or atypical Cache-Control headers involving qualified and unqualified private directives. In those conditions, the cache logic can incorrectly treat private responses as publicly cacheable, or the header parsing can throw an uncaught TypeError that propagates back to the application. The issue is specific to the interceptor's shared caching behavior and the parser's error handling, and does not affect clients that avoid the cache interceptor entirely.
Exploit preconditions
- Attack surface: HTTP responses processed by undici's cache interceptor in shared mode.
- Required access: Ability to influence Cache-Control headers on responses (e.g., as an origin server, API, or upstream service).
- Trigger point (data exposure): A response is returned with a degenerate qualified private directive (such as
privatewith an empty or malformed value), leading the cache interceptor to store content in the shared cache under a reusable key. - Trigger point (process error): A response includes a Cache-Control header that mixes an unqualified
privatedirective with a qualifiedprivatedirective, causing the cache-control parser to throw an uncaught TypeError. - Why exploitation is possible: The cache interceptor misinterprets malformed private directives as cacheable in a shared store and the parser lacks robust handling for mixed private directives, allowing both incorrect caching semantics and unhandled exceptions.
- Attack surface: HTTP responses processed by undici's cache interceptor in shared mode.
- Required access: Ability to influence Cache-Control headers on responses (e.g., as an origin server, API, or upstream service).
- Trigger point (data exposure): A response is returned with a degenerate qualified private directive (such as
privatewith an empty or malformed value), leading the cache interceptor to store content in the shared cache under a reusable key. - Trigger point (process error): A response includes a Cache-Control header that mixes an unqualified
privatedirective with a qualifiedprivatedirective, causing the cache-control parser to throw an uncaught TypeError. - Why exploitation is possible: The cache interceptor misinterprets malformed private directives as cacheable in a shared store and the parser lacks robust handling for mixed private directives, allowing both incorrect caching semantics and unhandled exceptions.
Why this happens
The underlying bug class maps to CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, combined with parsing robustness issues related to CWE-248: Uncaught Exception and CWE-525: Use of Web Browser Cache Containing Sensitive Information.
At an abstract level, the cache interceptor trusts Cache-Control headers without defensively handling malformed or edge-case combinations of private directives. Private responses with degenerate qualifiers are treated as suitable for a shared cache, breaking the intended isolation between per-user content and shared stores. Simultaneously, the cache-control parser assumes certain syntactic invariants and does not gracefully recover from mixed unqualified and qualified private directives, causing TypeErrors to bubble up unhandled. This combination of insecure caching semantics and brittle parsing logic leads to both data exposure and process stability risks.
The underlying bug class maps to CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, combined with parsing robustness issues related to CWE-248: Uncaught Exception and CWE-525: Use of Web Browser Cache Containing Sensitive Information.
At an abstract level, the cache interceptor trusts Cache-Control headers without defensively handling malformed or edge-case combinations of private directives. Private responses with degenerate qualifiers are treated as suitable for a shared cache, breaking the intended isolation between per-user content and shared stores. Simultaneously, the cache-control parser assumes certain syntactic invariants and does not gracefully recover from mixed unqualified and qualified private directives, causing TypeErrors to bubble up unhandled. This combination of insecure caching semantics and brittle parsing logic leads to both data exposure and process stability risks.
Potential impact
- Private response bodies may be served to other callers sharing the same cache key.
- Sensitive headers, including
Set-Cookie, could be disclosed to unauthorized clients. - Session identifiers and authentication tokens can be unintentionally leaked across users.
- Cache poisoning scenarios may arise where one client's private data influences another client's responses.
- Uncaught TypeErrors in the cache-control parser can reject legitimate responses and, depending on error handling, terminate the process or degrade availability.
- Private response bodies may be served to other callers sharing the same cache key.
- Sensitive headers, including
Set-Cookie, could be disclosed to unauthorized clients. - Session identifiers and authentication tokens can be unintentionally leaked across users.
- Cache poisoning scenarios may arise where one client's private data influences another client's responses.
- Uncaught TypeErrors in the cache-control parser can reject legitimate responses and, depending on error handling, terminate the process or degrade availability.
General mitigation guidance
Mitigation centers on tightening cache semantics around private content and hardening header parsing behavior.
Pattern-based defensive strategies include:
- Treating any response marked
private(qualified or unqualified) as non-cacheable in shared stores by default, unless explicitly and safely scoped to a single caller. - Implementing strict, fault-tolerant parsing for Cache-Control headers that either normalizes or conservatively rejects malformed directives without throwing uncaught exceptions.
- Separating per-user or session-specific caches from shared caches, ensuring private data cannot be keyed or reused across callers.
- Applying a "secure-by-default" posture in caching layers, where ambiguous or malformed cache directives result in non-caching rather than shared storage.
- Minimizing reliance on HTTP caching for responses carrying authentication, session, or other sensitive headers, or ensuring those responses are explicitly marked as non-cacheable.
Mitigation centers on tightening cache semantics around private content and hardening header parsing behavior.
Pattern-based defensive strategies include:
- Treating any response marked
private(qualified or unqualified) as non-cacheable in shared stores by default, unless explicitly and safely scoped to a single caller. - Implementing strict, fault-tolerant parsing for Cache-Control headers that either normalizes or conservatively rejects malformed directives without throwing uncaught exceptions.
- Separating per-user or session-specific caches from shared caches, ensuring private data cannot be keyed or reused across callers.
- Applying a "secure-by-default" posture in caching layers, where ambiguous or malformed cache directives result in non-caching rather than shared storage.
- Minimizing reliance on HTTP caching for responses carrying authentication, session, or other sensitive headers, or ensuring those responses are explicitly marked as non-cacheable.
How teams detect issues like this
High-level detection approaches can focus on both runtime behavior and code-level signals:
- Static analysis and code review: Look for use of shared caching mechanisms that treat
privateresponses as cacheable, especially around cache interceptors and HTTP client wrappers. Flag custom cache-control parsers that lack robust error handling or fallback behavior for unexpected directive combinations. - Policy enforcement: Define internal guidelines prohibiting shared caching of responses containing
Set-Cookieor other sensitive headers, and enforce these policies via automated checks in CI pipelines. - Runtime monitoring: Instrument logging around cache insert and retrieval operations to capture when private responses are stored in shared caches, and alert on anomalies such as user B receiving cache entries originally produced for user A.
- Exception tracking: Monitor for uncaught TypeErrors or similar exceptions in the HTTP caching code paths. Tools such as application performance monitoring and error aggregation services can surface recurring parser failures triggered by specific Cache-Control patterns.
High-level detection approaches can focus on both runtime behavior and code-level signals:
- Static analysis and code review: Look for use of shared caching mechanisms that treat
privateresponses as cacheable, especially around cache interceptors and HTTP client wrappers. Flag custom cache-control parsers that lack robust error handling or fallback behavior for unexpected directive combinations. - Policy enforcement: Define internal guidelines prohibiting shared caching of responses containing
Set-Cookieor other sensitive headers, and enforce these policies via automated checks in CI pipelines. - Runtime monitoring: Instrument logging around cache insert and retrieval operations to capture when private responses are stored in shared caches, and alert on anomalies such as user B receiving cache entries originally produced for user A.
- Exception tracking: Monitor for uncaught TypeErrors or similar exceptions in the HTTP caching code paths. Tools such as application performance monitoring and error aggregation services can surface recurring parser failures triggered by specific Cache-Control patterns.
Sources
| Source | Link |
|---|---|
| cna. | cna.openjsf.org/ |
| github. | github.com/ |

