CVE-2023-22795
Description
A regular expression based DoS vulnerability in Action Dispatch <6.1.7.1 and <7.0.4.1 related to the If-None-Match header. A specially crafted HTTP If-None-Match header can cause the regular expression engine to enter a state of catastrophic backtracking, when on a version of Ruby below 3.2.0. This can cause the process to use large amounts of CPU and memory, leading to a possible DoS vulnerability All users running an affected release should either upgrade or use one of the workarounds immediately.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
ReDoS vulnerability in Ruby on Rails Action Dispatch allows attacker-crafted If-None-Match headers to cause catastrophic backtracking, leading to denial of service.
Vulnerability
Overview
A regular expression denial-of-service (ReDoS) vulnerability exists in the Action Dispatch component of Ruby on Rails versions prior to 6.1.7.1 and 7.0.4.1. The vulnerability is triggered by a specially crafted If-None-Match HTTP header that causes the regular expression engine to enter catastrophic backtracking, resulting in excessive CPU and memory consumption. This issue is exploitable only on Ruby versions below 3.2.0, as Ruby 3.2.0 introduced changes to mitigate such ReDoS patterns [1][2].
Exploitation
The attack vector is remote and requires no authentication. An attacker sends an HTTP request with a malicious If-None-Match header to an affected Rails application. The server processes this header against a vulnerable regular expression, leading to exponential backtracking. No special privileges or user interaction is needed; the mere processing of the request by Action Dispatch triggers the vulnerability [1].
Impact
Successful exploitation causes the server process to consume large amounts of CPU and memory, significantly degrading performance and potentially leading to a complete denial of service (DoS) for legitimate users. Since the If-None-Match header is commonly processed in HTTP request handling, many Rails endpoints could be affected [1][3].
Mitigation
Users should upgrade to Rails 6.1.7.1, 7.0.4.1, or later where the vulnerability is patched. For those unable to upgrade, a workaround involves applying a monkey-patch to avoid the vulnerable regular expression, as detailed in the Rails advisory. The fix, visible in commit 8dc4595, modifies the regex to prevent catastrophic backtracking [2]. No CVSS score has been officially published as of the CVE date [1].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
actionpackRubyGems | >= 4.0.0.beta1, < 6.1.7.1 | 6.1.7.1 |
actionpackRubyGems | >= 7.0.0, < 7.0.4.1 | 7.0.4.1 |
Affected products
10- Action Dispatch/Action Dispatchdescription
- ghsa-coords9 versionspkg:gem/actionpackpkg:rpm/opensuse/rubygem-actionpack-5_1&distro=openSUSE%20Leap%2015.4pkg:rpm/opensuse/rubygem-actionpack-7.0&distro=openSUSE%20Tumbleweedpkg:rpm/suse/rubygem-actionpack-4_2&distro=SUSE%20OpenStack%20Cloud%20Crowbar%208pkg:rpm/suse/rubygem-actionpack-4_2&distro=SUSE%20OpenStack%20Cloud%20Crowbar%209pkg:rpm/suse/rubygem-actionpack-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015%20SP1pkg:rpm/suse/rubygem-actionpack-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015%20SP2pkg:rpm/suse/rubygem-actionpack-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015%20SP3pkg:rpm/suse/rubygem-actionpack-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015%20SP4
>= 4.0.0.beta1, < 6.1.7.1+ 8 more
- (no CPE)range: >= 4.0.0.beta1, < 6.1.7.1
- (no CPE)range: < 5.1.4-150000.3.15.1
- (no CPE)range: < 7.0.4.1-1.1
- (no CPE)range: < 4.2.9-7.15.1
- (no CPE)range: < 4.2.9-7.15.1
- (no CPE)range: < 5.1.4-150000.3.15.1
- (no CPE)range: < 5.1.4-150000.3.15.1
- (no CPE)range: < 5.1.4-150000.3.15.1
- (no CPE)range: < 5.1.4-150000.3.15.1
Patches
38dc45950619aAvoid regex backtracking on If-None-Match header
1 file changed · +1 −1
actionpack/lib/action_dispatch/http/cache.rb+1 −1 modified@@ -18,7 +18,7 @@ def if_none_match end def if_none_match_etags - if_none_match ? if_none_match.split(/\s*,\s*/) : [] + if_none_match ? if_none_match.split(",").each(&:strip!) : [] end def not_modified?(modified_at)
8d82687f3b04Avoid regex backtracking on If-None-Match header
1 file changed · +1 −1
actionpack/lib/action_dispatch/http/cache.rb+1 −1 modified@@ -18,7 +18,7 @@ def if_none_match end def if_none_match_etags - if_none_match ? if_none_match.split(/\s*,\s*/) : [] + if_none_match ? if_none_match.split(",").each(&:strip!) : [] end def not_modified?(modified_at)
cd461c3e64e0Support for multiple etags in an If-None-Match header
3 files changed · +48 −1
actionpack/CHANGELOG.md+2 −0 modified@@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Support multiple etags in If-None-Match header. *Travis Warlick* + * Allow to configure how unverified request will be handled using `:with` option in `protect_from_forgery` method.
actionpack/lib/action_dispatch/http/cache.rb+7 −1 modified@@ -17,12 +17,18 @@ def if_none_match env[HTTP_IF_NONE_MATCH] end + def if_none_match_etags + (if_none_match ? if_none_match.split(/\s*,\s*/) : []).collect do |etag| + etag.gsub(/^\"|\"$/, "") + end + end + def not_modified?(modified_at) if_modified_since && modified_at && if_modified_since >= modified_at end def etag_matches?(etag) - if_none_match && if_none_match == etag + if_none_match_etags.include?(etag) end # Check response freshness (Last-Modified and ETag) against request
actionpack/test/dispatch/request_test.rb+39 −0 modified@@ -746,6 +746,45 @@ def url_for(options = {}) assert_equal "/foo?bar", path end + test "if_none_match_etags none" do + request = stub_request + + assert_equal nil, request.if_none_match + assert_equal [], request.if_none_match_etags + assert !request.etag_matches?("foo") + assert !request.etag_matches?(nil) + end + + test "if_none_match_etags single" do + header = 'the-etag' + request = stub_request('HTTP_IF_NONE_MATCH' => header) + + assert_equal header, request.if_none_match + assert_equal [header], request.if_none_match_etags + assert request.etag_matches?("the-etag") + end + + test "if_none_match_etags quoted single" do + header = '"the-etag"' + request = stub_request('HTTP_IF_NONE_MATCH' => header) + + assert_equal header, request.if_none_match + assert_equal ['the-etag'], request.if_none_match_etags + assert request.etag_matches?("the-etag") + end + + test "if_none_match_etags multiple" do + header = 'etag1, etag2, "third etag", "etag4"' + expected = ['etag1', 'etag2', 'third etag', 'etag4'] + request = stub_request('HTTP_IF_NONE_MATCH' => header) + + assert_equal header, request.if_none_match + assert_equal expected, request.if_none_match_etags + expected.each do |etag| + assert request.etag_matches?(etag), etag + end + end + protected def stub_request(env = {})
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
12- github.com/advisories/GHSA-8xww-x3g3-6jcvghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-22795ghsaADVISORY
- www.debian.org/security/2023/dsa-5372mitrevendor-advisory
- discuss.rubyonrails.org/t/cve-2023-22795-possible-redos-based-dos-vulnerability-in-action-dispatch/82118ghsaWEB
- github.com/rails/rails/commit/8d82687f3b04b2803320b64f985308239a8c3d2fghsaWEB
- github.com/rails/rails/commit/8dc45950619a4c64d16fb9370570c996d201f9b0ghsaWEB
- github.com/rails/rails/commit/cd461c3e64e09cdcb1e379d1c35423c5e2caa592ghsaWEB
- github.com/rails/rails/releases/tag/v6.1.7.1ghsaWEB
- github.com/rails/rails/releases/tag/v7.0.4.1ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/actionpack/CVE-2023-22795.ymlghsaWEB
- rubyonrails.org/2023/1/17/Rails-Versions-6-0-6-1-6-1-7-1-7-0-4-1-have-been-releasedghsaWEB
- security.netapp.com/advisory/ntap-20240202-0010/mitre
News mentions
0No linked articles in our index yet.