CVE-2025-61598 Overview
CVE-2025-61598 affects Discourse, an open source discussion platform used by thousands of online communities. Versions before 3.6.2 and 3.6.0.beta2 omit the default Cache-Control: no-store, no-cache response header from error responses. Intermediary proxies and caching layers may store these error responses and serve them to other users. This condition can enable cache poisoning attacks where attackers influence what cached error content reaches legitimate visitors. The issue is classified under [CWE-524] (Use of Cache Containing Sensitive Information) and is fixed in Discourse 3.6.2 and 3.6.0.beta2.
Critical Impact
Missing cache directives on error responses can lead to cache poisoning by upstream proxies, potentially serving manipulated or stale error content to legitimate users of Discourse forums.
Affected Products
- Discourse stable versions before 3.6.2
- Discourse beta versions before 3.6.0.beta2
- Discourse 3.6.0.beta1
Discovery Timeline
- 2025-10-28 - CVE CVE-2025-61598 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-61598
Vulnerability Analysis
Discourse controllers apply a default Cache-Control: no-store, no-cache header on successful responses to prevent intermediaries from caching authenticated or dynamic content. Error responses generated through the public exceptions middleware bypassed this behavior. When the middleware invoked ApplicationController.rescue_with_handler to render an error page, the response body was extracted before the Rails response finalization logic ran the callbacks that set cache headers. Downstream proxies and CDNs treated these error responses as cacheable by default, opening the door to unintended storage and reuse.
Root Cause
The root cause is a missing invocation of the response finalization pipeline in lib/middleware/discourse_public_exceptions.rb. The around_action :ensure_dont_cache_page callback in ApplicationController was never applied to error paths because the response object was consumed before header-setting callbacks executed. Error responses left the application without explicit cache directives.
Attack Vector
An unauthenticated remote attacker triggers an error condition on a Discourse endpoint routed through a shared caching proxy. The proxy stores the uncached error response and serves it to subsequent requesters keyed on the same URL. Depending on the deployment topology, this can be leveraged for cache poisoning against other users of the same forum.
# Patch: app/controllers/application_controller.rb
end
end
+ around_action :ensure_dont_cache_page
before_action :check_readonly_mode
before_action :handle_theme
before_action :set_current_user_for_logs
# Patch: lib/middleware/discourse_public_exceptions.rb
end
if ApplicationController.rescue_with_handler(exception, object: fake_controller)
+ # Calling `ActionDispatch::Response#to_a` here to ensure that cache control headers are set.
+ response.to_a
body = response.body
body = [body] if String === body
rack_response = [response.status, response.headers, body]
Source: Discourse commit 3ea1b663 and Discourse commit fd567af7
Detection Methods for CVE-2025-61598
Indicators of Compromise
- HTTP error responses (4xx/5xx) returned by Discourse without a Cache-Control header set to no-store, no-cache.
- Cached error pages being served by upstream CDNs or reverse proxies for authenticated Discourse routes.
- Anomalous consistency in error content presented to different users for identical URLs when cache tiers are involved.
Detection Strategies
- Query CDN and reverse proxy access logs for cache HIT responses on Discourse error status codes.
- Fingerprint deployed Discourse versions and compare against 3.6.2 (stable) or 3.6.0.beta2 (beta).
- Inspect HTTP response headers from Discourse error endpoints for missing or permissive Cache-Control values.
Monitoring Recommendations
- Enable header logging at the reverse proxy tier to record Cache-Control and X-Cache values for all Discourse responses.
- Alert on unexpected cache hits for URLs that return non-200 status codes.
- Track Discourse version disclosures across the fleet and flag installations still running vulnerable releases.
How to Mitigate CVE-2025-61598
Immediate Actions Required
- Upgrade Discourse stable installations to version 3.6.2 or later.
- Upgrade Discourse beta installations to 3.6.0.beta2 or later.
- Purge cached error responses from CDNs and reverse proxies fronting Discourse.
Patch Information
The fix is delivered in Discourse 3.6.2 and 3.6.0.beta2. The patch adds an around_action :ensure_dont_cache_page callback in ApplicationController and forces response finalization in discourse_public_exceptions.rb by calling response.to_a before extracting the body. Details are available in the GitHub Security Advisory GHSA-jp9x-wwv6-cv3j.
Workarounds
- Configure the reverse proxy or CDN to force Cache-Control: no-store, no-cache on all Discourse error responses until the patch is applied.
- Disable caching of non-200 responses at the CDN layer for the Discourse origin.
- Restrict shared caches from storing responses for authenticated Discourse routes.
# Example nginx override to enforce no-store on Discourse error responses
map $status $discourse_no_cache {
default "";
~^[45] "no-store, no-cache";
}
server {
location / {
proxy_pass http://discourse_upstream;
add_header Cache-Control $discourse_no_cache always;
}
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

