CVE-2026-126073: Rails Action Pack: missing Vary enables cache poisoning

GHSA-r9jg-fmfx-2gv6MEDIUM
Published November 10, 2026
CISO Take

Rails Action Pack (actionpack 8.1 before 8.1.4.1) can omit the Vary headers that select a response's format, so a shared cache may store one representation and serve it to clients requesting another, for example HTML without its layout where JSON was expected. This is a generic web framework flaw rather than an AI-specific one, and exposure to AI workloads is limited to Rails-based LLM API gateways and dashboards. Risk is low to moderate: CVSS is 4.8, there is no known exploit, no Nuclei template, no KEV listing, and EPSS is unavailable. The attacker cannot control response content, and only apps that mark negotiated responses public behind a Vary-honouring cache such as Thruster or Rack::Cache are affected. With 6,440 dependents the footprint is broad, so upgrade to 8.1.4.1 (8.0.5.2 for the 8.0 line) on a normal patch cycle, or add Vary: Accept, X-Requested-With to negotiated responses.

Sources:NVDGitHub AdvisoryATLASOpenSSF

What is the risk?

Medium-low. Exploitation needs high attack complexity: a public-cached, format-negotiated action behind a shared cache that honours Vary. The attacker cannot choose response content, so impact is limited to integrity and availability degradation (wrong format served until cache expiry). No confidentiality impact, no known exploitation, no public exploit, and no CISA KEV or SSVC signal. AI relevance is indirect and applies only to Rails apps fronting LLM or ML APIs through a shared cache.

How does the attack unfold?

Initial Access
The attacker sends a request without an Accept header, or an XHR request, to a public-cacheable negotiated endpoint.
AML.T0049
Cache Poisoning
The shared cache stores the response without Vary: Accept because Action Pack omitted the header.
Impact
Later clients requesting a different format receive the wrong representation, such as HTML instead of JSON, until the entry expires.

What systems are affected?

PackageEcosystemVulnerable RangePatched
Anthropic Pythonrubygems>= 8.1, < 8.1.4.18.1.4.1
4.1K6.4K dependentsPushed 8d ago94% patched~11d to patchFull package profile →

Do you use Anthropic Python? You're affected.

How severe is it?

CVSS 3.1
4.8 / 10
EPSS
0.4%
chance of exploitation in 30 days
Higher than 37% of all CVEs
Exploitation Status
No known exploitation
Sophistication
Moderate

What is the attack surface?

AVACPRUISCIA
AVNetwork
ACHigh
PRNone
UINone
SUnchanged
CNone
ILow
ALow

What should I do?

1 step
  1. 1) Upgrade actionpack to 8.1.4.1 or 8.0.5.2. 2) If you cannot upgrade, apply the vendor patches (commits 7a955ca for 8.1 and b58c107 for 8.0). 3) Workaround: set Vary: Accept, X-Requested-With in an after_action on negotiated responses, or stop marking negotiated responses public. 4) Audit actions using expires_in with public: true behind Thruster, Rack::Cache or a CDN that honours Vary. 5) Detection: look for cache hits returning a Content-Type that does not match the request's Accept header, and review shared cache keys for format variance. 6) After patching, expect more cache variants per URL and monitor hit rates.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

ISO 42001
A.6.2.6-AI system operation and monitoring
NIST AI RMF
MANAGE 2.3-Mechanisms to respond to and recover from unknown risks

Frequently Asked Questions

What is CVE-2026-126073?

Rails Action Pack (actionpack 8.1 before 8.1.4.1) can omit the Vary headers that select a response's format, so a shared cache may store one representation and serve it to clients requesting another, for example HTML without its layout where JSON was expected. This is a generic web framework flaw rather than an AI-specific one, and exposure to AI workloads is limited to Rails-based LLM API gateways and dashboards. Risk is low to moderate: CVSS is 4.8, there is no known exploit, no Nuclei template, no KEV listing, and EPSS is unavailable. The attacker cannot control response content, and only apps that mark negotiated responses public behind a Vary-honouring cache such as Thruster or Rack::Cache are affected. With 6,440 dependents the footprint is broad, so upgrade to 8.1.4.1 (8.0.5.2 for the 8.0 line) on a normal patch cycle, or add Vary: Accept, X-Requested-With to negotiated responses.

Is CVE-2026-126073 actively exploited?

No confirmed active exploitation of CVE-2026-126073 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-126073?

1) Upgrade actionpack to 8.1.4.1 or 8.0.5.2. 2) If you cannot upgrade, apply the vendor patches (commits 7a955ca for 8.1 and b58c107 for 8.0). 3) Workaround: set Vary: Accept, X-Requested-With in an after_action on negotiated responses, or stop marking negotiated responses public. 4) Audit actions using expires_in with public: true behind Thruster, Rack::Cache or a CDN that honours Vary. 5) Detection: look for cache hits returning a Content-Type that does not match the request's Accept header, and review shared cache keys for format variance. 6) After patching, expect more cache variants per URL and monitor hit rates.

What systems are affected by CVE-2026-126073?

This vulnerability affects the following AI/ML architecture patterns: Rails-based LLM API gateways, Model serving dashboards, Web frontends for AI applications, Shared HTTP cache layers (Thruster, Rack::Cache).

What is the CVSS score for CVE-2026-126073?

CVE-2026-126073 has a CVSS v3.1 base score of 4.8 (MEDIUM). The EPSS exploitation probability is 0.42%.

What is the AI security impact?

Affected AI Architectures

Rails-based LLM API gatewaysModel serving dashboardsWeb frontends for AI applicationsShared HTTP cache layers (Thruster, Rack::Cache)

MITRE ATLAS Techniques

AML.T0049Exploit Public-Facing Application

Compliance Controls Affected

ISO 42001: A.6.2.6
NIST AI RMF: MANAGE 2.3

What are the technical details?

Original Advisory

### Impact Action Pack negotiates the format of a rendered response from the `Accept`, `X-Requested-With` and, for XHR requests without `Accept`, `Content-Type` request headers, but `ActionController::Rendering#_set_vary_header` adds `Vary: Accept` only when the request carries a usable `Accept` header and the response has no `Vary` header yet. A response to a request without `Accept`, or to an XHR request, therefore omits the headers that selected its representation, and a response whose `Vary` the application set before rendering (for example `Vary: Accept-Language`) never gains `Accept`. A shared cache that honours `Vary` could store such a response and serve it to later clients that request a different representation, possibly leading to cache poisoning in which visitors receive, until the entry expires, a page without its layout or HTML in place of JSON. The attacker cannot choose the content of the response. Applications that render negotiated responses from actions marked `public` (for example with `expires_in ..., public: true`) behind a shared cache that honours `Vary`, such as Thruster or `Rack::Cache`, are affected. ### Details In the fixed releases, a rendered response whose format is not given by the URL lists `Accept` and `X-Requested-With` in `Vary`, and also `Content-Type` for an XHR request without `Accept`; when `config.action_dispatch.ignore_accept_header` is enabled, it lists only `X-Requested-With`. These fields are appended to an existing `Vary` value rather than skipped, and `Vary: *` is left unchanged. Shared caches can store more variants of such responses than before. See the Action Pack CHANGELOG for details. ### Workarounds Set `Vary: Accept, X-Requested-With` on negotiated responses in the application, for example in an `after_action`, or do not mark negotiated responses `public`. ### Releases The fixed releases are available at the normal locations. Patches for those who cannot upgrade at once: - 8.1: https://github.com/rails/rails/commit/7a955ca36779938267c93902c47d1f55bab99b4b.patch - 8.0: https://github.com/rails/rails/commit/b58c107abe9c1f10c1d6a4941402c60e4dc4742c.patch ### Credit This issue was found by the Anthropic OSS Scanner (ANT-2026-7GHGLQGO, ANT-2026-5MT6C2R3).

Exploitation Scenario

An attacker sends a request without an Accept header, or an XHR request, to a public-cacheable endpoint of a Rails app that proxies an LLM inference API, behind Thruster or Rack::Cache. The response is cached without Vary: Accept. Later legitimate clients requesting JSON receive the cached layout-less HTML, or the reverse, until the entry expires. The result is a broken UI or failed API calls for AI agent integrations. The attacker cannot inject content of their choosing.

Weaknesses (CWE)

CWE-436 — Interpretation Conflict: Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L

Timeline

Published
November 10, 2026
Last Modified
November 12, 2026
First Seen
November 11, 2026

Related Vulnerabilities