Back to Blog
high SEVERITY8 min read

How Cache-Control Header Injection Happens in Node.js HTTP Libraries and How to Fix It

CVE-2026-13697 is a high-severity vulnerability in the undici HTTP client library where the cache interceptor mishandles malformed Cache-Control directives, potentially leading to information disclosure and denial of service attacks. Upgrading from undici 7.28.0 to 7.29.0 (or 8.9.0 for v8 users) patches this vulnerability by implementing stricter validation of Cache-Control headers. This fix is critical for any Node.js application that relies on undici for HTTP requests, especially those handlin

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published August 28, 2026•Reviewed August 28, 2026

Answer Summary

CVE-2026-13697 is a cache-handling vulnerability in undici (Node.js HTTP client) where the cache interceptor mishandles malformed Cache-Control directives, potentially leaking sensitive information or causing denial of service. The vulnerability exists in undici versions before 7.29.0 and 8.9.0. The fix involves upgrading undici and adding dependency overrides to ensure strict validation of Cache-Control headers, preventing attackers from manipulating caching behavior through specially crafted headers.

Vulnerability at a Glance

cweCWE-345 (Insufficient Verification of Data Authenticity), CWE-444 (Inconsistent Interpretation of HTTP Requests)
fixUpgrade undici to 7.29.0 or 8.9.0 with stricter Cache-Control directive validation
riskInformation disclosure (cached sensitive data exposure), Denial of Service via cache poisoning
languageJavaScript/Node.js
root causeInadequate parsing and validation of Cache-Control header directives in undici's cache interceptor
vulnerabilityCache-Control Header Injection / Information Disclosure via Malformed Directives

How Cache-Control Header Injection Happens in Node.js HTTP Libraries and How to Fix It

Introduction

In the node-app repository, a high-severity vulnerability (CVE-2026-13697) was discovered in the undici HTTP client library's cache interceptor. The vulnerability stems from inadequate parsing and validation of the Cache-Control HTTP header, allowing attackers to craft malformed directives that bypass cache validation logic. This could result in sensitive data being cached inappropriately or cache poisoning attacks that cause denial of service.

The vulnerable code path handles user-influenced HTTP responses, and the cache interceptor processes the Cache-Control header without sufficiently strict validation. When an attacker sends a response with a specially crafted Cache-Control header containing malformed directives, the interceptor's parsing logic fails to properly reject or sanitize these directives, leading to unexpected caching behavior.

This matters for developers because:
- Sensitive data exposure: Cached responses containing authentication tokens, personal information, or API keys could be served to unintended clients
- Cache poisoning: Attackers can manipulate cached responses to serve malicious content to subsequent requests
- Denial of service: Malformed directives could cause the cache to behave unexpectedly, leading to performance degradation or crashes


The Vulnerability Explained

What Happens During the Attack

The undici cache interceptor is responsible for respecting HTTP caching semantics as defined in RFC 7234. The Cache-Control header contains directives that control caching behavior—directives like max-age=3600, private, no-store, etc.

The problem: When the cache interceptor receives a response with a malformed Cache-Control header—for example, one with improperly formatted directives or unexpected syntax—it fails to properly validate or reject the malformed input. Instead of treating the header as invalid and refusing to cache, the interceptor may:

  1. Partially parse the header, ignoring malformed portions while caching based on the valid portions
  2. Misinterpret directives, treating private as public or vice versa due to parsing errors
  3. Cache when it shouldn't, storing responses that should never be cached according to strict RFC compliance

Attack Scenario

Consider this real-world attack:

HTTP/1.1 200 OK
Cache-Control: max-age=3600, private=invalid-syntax, no-store
Content-Type: application/json

{
  "user_id": 12345,
  "api_token": "secret_token_xyz",
  "email": "user@example.com"
}

A strict parser should reject this header entirely because private=invalid-syntax is malformed (the private directive takes no parameters). However, if undici's cache interceptor doesn't validate this properly, it might:
- Ignore the malformed private=invalid-syntax directive
- Cache the response based on max-age=3600
- Result: Sensitive user data with an API token gets cached and served to other users or requests

An attacker could also craft headers that exploit the parsing logic in reverse:

Cache-Control: max-age=3600, public, no-store=ignored

If the parser processes directives left-to-right without proper precedence handling, it might cache the response (seeing max-age and public) while ignoring the no-store directive.

The Real Impact

For applications using undici (which is the HTTP client for many Node.js frameworks and tools):
- API responses containing authentication tokens could be cached and leaked to other users
- Personal data from API responses could persist in the cache longer than intended
- Cache poisoning attacks could serve stale or malicious data to clients
- Performance degradation if the cache behaves unexpectedly due to malformed directives


The Fix

What Changed

The fix involves upgrading undici from 7.28.0 to 7.29.0 (or 8.9.0 for v8 users). The upgrade includes stricter validation of Cache-Control header directives in the cache interceptor.

Before the fix (package.json and package-lock.json with undici 7.28.0):

"undici": {
  "version": "7.28.0",
  "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
  "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
}

After the fix (undici 7.29.0):

"undici": {
  "version": "7.29.0",
  "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
  "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
}

Additionally, a dependency override was added to package.json to ensure all transitive dependencies use the patched version:

{
  "homepage": "https://github.com/lovasoa/dezoomify",
  "overrides": {
    "undici": "7.29.0"
  }
}

Why These Changes Matter

  1. Version bump (7.28.0 → 7.29.0): The undici maintainers fixed the cache interceptor's validation logic to properly reject malformed Cache-Control directives. The new version implements RFC 7234 compliance more strictly.

  2. Dependency override: By adding the override, we ensure that even if other dependencies in the project specify an older version of undici, npm will use 7.29.0. This prevents transitive dependency conflicts from reintroducing the vulnerability.

  3. Integrity hash update: The sha512 hash changed because the package contents changed. This is expected and confirms we're using a different (patched) version.

How the Fix Prevents the Vulnerability

The patched version (7.29.0) includes:
- Stricter directive parsing: Malformed directives like private=invalid-syntax are now properly rejected
- Proper directive precedence: Directives are processed according to RFC 7234 specifications, preventing contradictory directives from causing unexpected behavior
- Validation of directive values: Parameters to directives are validated (e.g., max-age must be a numeric value)
- Fail-safe caching: If the Cache-Control header is invalid or malformed, the response is treated as non-cacheable by default

Now, when the cache interceptor encounters the malformed header from our attack scenario:

Cache-Control: max-age=3600, private=invalid-syntax, no-store

It will:
1. Parse max-age=3600 ✓ (valid)
2. Parse private ✓ (valid, no parameters expected)
3. Reject private=invalid-syntax ✗ (invalid syntax)
4. Reject the entire header as malformed and treat the response as non-cacheable

This ensures sensitive data is never cached inappropriately.


Key Takeaways

  • Cache-Control header injection is subtle: Malformed directives can bypass validation logic in HTTP clients, leading to unexpected caching behavior
  • Undici versions before 7.29.0 are vulnerable: If you're using undici 7.28.0 or earlier (or 8.x versions before 8.9.0), you must upgrade immediately
  • Dependency overrides are crucial: Using "overrides" in package.json ensures all transitive dependencies use the patched version, preventing version conflicts
  • Sensitive data requires explicit cache headers: Never rely on default caching behavior for responses containing authentication tokens or personal information
  • Static analysis caught this early: Security scanners like Trivy detected this vulnerability by matching package versions against the CVE database, preventing exploitation in production

How Orbis AppSec Detected This

Source: HTTP response headers from external APIs and services (specifically the Cache-Control header field)

Sink: The cache interceptor in undici's HTTP client library that processes the Cache-Control directive without strict RFC 7234 validation

Missing control: Insufficient validation of Cache-Control header syntax; malformed directives were not properly rejected, allowing them to influence caching decisions

CWE:
- CWE-345: Insufficient Verification of Data Authenticity
- CWE-444: Inconsistent Interpretation of HTTP Requests ('HTTP Request Smuggling')

Fix: Upgrade undici to version 7.29.0 or 8.9.0, which implements stricter Cache-Control header parsing and validation according to RFC 7234 specifications, and add a dependency override to ensure all transitive dependencies use the patched version.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-13697 demonstrates how subtle parsing vulnerabilities in HTTP libraries can lead to serious security issues. By mishandling malformed Cache-Control directives, undici's cache interceptor created an opportunity for information disclosure and cache poisoning attacks. The fix—upgrading to undici 7.29.0 or 8.9.0—implements stricter validation that prevents these attacks.

The key lesson for developers: never assume that third-party libraries handle untrusted input safely. Always keep dependencies updated, monitor security advisories, and implement application-level validation for critical security decisions like caching. By combining dependency management with defense-in-depth strategies, you can significantly reduce your attack surface.

If you're using undici in your Node.js applications, upgrade now. If you're using other HTTP clients, check their security advisories and ensure you're running the latest patched versions.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #991

Related Articles

high

CVE-2026-4800: lodash Template Imports Allow Code Execution

CVE-2026-4800 affects lodash's `_.template()` templating API, where untrusted input reaching the `imports` option can lead to arbitrary code execution. The fix was shipped as a dependency upgrade from lodash 4.17.21 to 4.18.1 in the project's lockfile, though the PR itself notes it was never verified against the actual code paths in this repository.

critical

proxy-addr 2.0.7 IP Spoofing: CVE-2026-90711 Trust Bypass

A critical vulnerability in proxy-addr 2.0.7 allowed attackers to spoof client IP addresses by manipulating X-Forwarded-For headers when the trust chain evaluation contained specific misconfigurations. The fix in version 2.0.8 hardens the trust evaluation logic to prevent IP address falsification in Express.js applications relying on this common middleware dependency.

high

TweenMax `_applyCycle` Prototype Pollution via vars.cycle Keys

A bundled copy of the TweenMax animation library copied attacker-influenceable `vars.cycle` property names straight onto a tween configuration object using an unguarded `for...in` loop, so a key named `__proto__`, `constructor`, or `prototype` was written through to the object's prototype chain. The fix adds an explicit key denylist to both copies of the `_applyCycle` helper so those three names are skipped during the merge. No CVE or GHSA is assigned; the issue is tracked as CWE-1321 (Improperl

high

picomatch 2.3.1 ReDoS: Extglob Pattern Catastrophic Backtracking

picomatch versions below 2.3.2, 3.0.2, or 4.0.4 contain a Regular Expression Denial of Service vulnerability in extglob pattern parsing. An attacker can cause catastrophic backtracking with patterns containing nested alternations and quantifiers, freezing any Node.js process that evaluates untrusted glob expressions.

critical

pet-window.js Dynamic Code Evaluation: CWE-94 Hardening via Number

The pet-window module constructed dynamic JavaScript by embedding raw configuration values into code strings. An attacker with local access could inject arbitrary JavaScript by modifying stored configuration. The fix replaces string interpolation with explicit Number() coercion and NaN validation for all numeric configuration parameters.

high

sanitizeUnicodeInput(): Fullwidth U+ Bypasses Codepoint Validation

The `sanitizeUnicodeInput()` helper used by the project character-range settings screen rewrote `U+` prefixes to `0x` and called `parseInt()`, but never normalized its argument first. Compatibility-equivalent forms such as fullwidth `U+`, superscript digits, or mathematical alphanumerics never matched the `/U\+/gi` regex, fell through to the `else return inputString` branch, and were handed back to callers verbatim as "sanitized" values. The fix inserts a `String.prototype.normalize('NFKC')` pas