ACTIONPACK · GHSA-r9jg-fmfx-2gv6 · Package
FIX → 8.1.4.1 +1
Action Pack omits the Vary header that records which request headers chose a response's format, so a shared cache can store a response and serve it to clients asking for a different format. An attacker cannot choose the response content, but visitors may receive a page without its layout or HTML in place of JSON until the cache entry expires.
first public Nov 4, 2026 · 1 source
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Applications that render format-negotiated responses (HTML or JSON from the same action) from actions marked public and served through a shared cache that honours Vary, such as Thruster or Rack::Cache. Applications without public caching of negotiated responses, or without a shared cache in front, are unlikely to be exposed.
Not affected if no-public-caching, no-shared-cache, single-format-responses
Who cares actionpack, rails, ruby, self-hosted
bundle exec rails -v or check Gemfile.lock for actionpack below 8.1.4.1 or below 8.0.5.2.public (for example ) that render negotiated responses behind a cache such as Thruster or .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.
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
expires_in ..., public: trueRack::Cacheconfig.action_dispatch.ignore_accept_header is enabled.Upgrade to 8.1.4.1 +1
8.1.4.18.0.5.2Applications 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.
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.
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.
The fixed releases are available at the normal locations.
Patches for those who cannot upgrade at once:
This issue was found by the Anthropic OSS Scanner (ANT-2026-7GHGLQGO, ANT-2026-5MT6C2R3).