CVE-2022-22577
Description
An XSS Vulnerability in Action Pack >= 5.2.0 and < 5.2.0 that could allow an attacker to bypass CSP for non HTML like responses.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
An XSS vulnerability in Action Pack allows CSP bypass for non-HTML responses, affecting Rails 5.2.0 through 7.0.2.3.
Vulnerability
An XSS vulnerability exists in Action Pack (the controller and routing layer of Ruby on Rails) that allows an attacker to bypass Content Security Policy (CSP) for responses with non-HTML content types, such as JSON or XML [1][4]. The issue affects Rails versions 5.2.0 to 5.2.7.0, 6.0.0 to 6.0.4.7, 6.1.0 to 6.1.5.0, and 7.0.0 to 7.0.2.3 [2]. The vulnerability occurs because the CSP header is not properly enforced when the response's Content-Type is not text/html, potentially allowing injected scripts to execute without the intended CSP restrictions.
Exploitation
An attacker must be able to inject malicious content into a non-HTML response, typically through user-supplied data that is reflected in the response body (e.g., a JSON API endpoint that echoes input). The attacker crafts a request that results in a response with a non-HTML content type containing embedded JavaScript. Because the CSP header may be missing or ineffective for such responses, the injected script can execute in the victim's browser when the response is processed [1][4]. No authentication or special network position is required if the vulnerable endpoint is publicly accessible.
Impact
Successful exploitation leads to cross-site scripting (XSS) attacks, allowing the attacker to execute arbitrary JavaScript in the context of the victim's session. This can result in data theft, session hijacking, defacement, or other malicious actions depending on the application's functionality and the victim's privileges [1][4].
Mitigation
The vulnerability is fixed in Rails versions 5.2.7.1, 6.0.4.8, 6.1.5.1, and 7.0.2.4, released on April 26, 2022 [2]. Users should upgrade to these versions or later. No workaround is documented; upgrading is the recommended action.
AI Insight generated on May 21, 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 | >= 5.2.0, < 5.2.7.1 | 5.2.7.1 |
actionpackRubyGems | >= 6.0.0, < 6.0.4.8 | 6.0.4.8 |
actionpackRubyGems | >= 6.1.0, < 6.1.5.1 | 6.1.5.1 |
actionpackRubyGems | >= 7.0.0, < 7.0.2.4 | 7.0.2.4 |
Affected products
2- Action Pack/Action Packdescription
Patches
42b820a2a69faMerge pull request #44635 from imtayadeway/tjw/api-csp-i
3 files changed · +19 −7
actionpack/CHANGELOG.md+4 −0 modified@@ -1,3 +1,7 @@ +* Allow Content Security Policy DSL to generate for API responses. + + *Tim Wade* + ## Rails 6.1.5 (March 09, 2022) ## * Fix `content_security_policy` returning invalid directives.
actionpack/lib/action_dispatch/http/content_security_policy.rb+0 −7 modified@@ -18,7 +18,6 @@ def call(env) request = ActionDispatch::Request.new env _, headers, _ = response = @app.call(env) - return response unless html_response?(headers) return response if policy_present?(headers) if policy = request.content_security_policy @@ -32,12 +31,6 @@ def call(env) end private - def html_response?(headers) - if content_type = headers[CONTENT_TYPE] - /html/.match?(content_type) - end - end - def header_name(request) if request.content_security_policy_report_only POLICY_REPORT_ONLY
actionpack/test/dispatch/content_security_policy_test.rb+15 −0 modified@@ -385,6 +385,11 @@ class PolicyController < ActionController::Base content_security_policy_report_only only: :report_only + content_security_policy only: :api do |p| + p.default_src :none + p.frame_ancestors :none + end + def index head :ok end @@ -413,6 +418,10 @@ def no_policy head :ok end + def api + render json: {} + end + private def condition? params[:condition] == "true" @@ -429,6 +438,7 @@ def condition? get "/script-src", to: "policy#script_src" get "/style-src", to: "policy#style_src" get "/no-policy", to: "policy#no_policy" + get "/api", to: "policy#api" end end @@ -500,6 +510,11 @@ def test_generates_no_content_security_policy assert_nil response.headers["Content-Security-Policy-Report-Only"] end + def test_generates_api_security_policy + get "/api" + assert_policy "default-src 'none'; frame-ancestors 'none'" + end + private def assert_policy(expected, report_only: false) assert_response :success
5299b57d596eMerge pull request #44635 from imtayadeway/tjw/api-csp-i
3 files changed · +19 −7
actionpack/CHANGELOG.md+4 −0 modified@@ -1,3 +1,7 @@ +* Allow Content Security Policy DSL to generate for API responses. + + *Tim Wade* + ## Rails 6.0.4.7 (March 08, 2022) ## * No changes.
actionpack/lib/action_dispatch/http/content_security_policy.rb+0 −7 modified@@ -17,7 +17,6 @@ def call(env) request = ActionDispatch::Request.new env _, headers, _ = response = @app.call(env) - return response unless html_response?(headers) return response if policy_present?(headers) if policy = request.content_security_policy @@ -31,12 +30,6 @@ def call(env) end private - def html_response?(headers) - if content_type = headers[CONTENT_TYPE] - content_type =~ /html/ - end - end - def header_name(request) if request.content_security_policy_report_only POLICY_REPORT_ONLY
actionpack/test/dispatch/content_security_policy_test.rb+15 −0 modified@@ -353,6 +353,11 @@ class PolicyController < ActionController::Base content_security_policy_report_only only: :report_only + content_security_policy only: :api do |p| + p.default_src :none + p.frame_ancestors :none + end + def index head :ok end @@ -381,6 +386,10 @@ def no_policy head :ok end + def api + render json: {} + end + private def condition? params[:condition] == "true" @@ -397,6 +406,7 @@ def condition? get "/script-src", to: "policy#script_src" get "/style-src", to: "policy#style_src" get "/no-policy", to: "policy#no_policy" + get "/api", to: "policy#api" end end @@ -468,6 +478,11 @@ def test_generates_no_content_security_policy assert_nil response.headers["Content-Security-Policy-Report-Only"] end + def test_generates_api_security_policy + get "/api" + assert_policy "default-src 'none'; frame-ancestors 'none'" + end + private def assert_policy(expected, report_only: false) assert_response :success
8198d7c4accaMerge pull request #44635 from imtayadeway/tjw/api-csp-i
3 files changed · +19 −7
actionpack/CHANGELOG.md+4 −0 modified@@ -1,3 +1,7 @@ +* Allow Content Security Policy DSL to generate for API responses. + + *Tim Wade* + ## Rails 7.0.2.3 (March 08, 2022) ## * No changes.
actionpack/lib/action_dispatch/http/content_security_policy.rb+0 −7 modified@@ -17,7 +17,6 @@ def call(env) request = ActionDispatch::Request.new env _, headers, _ = response = @app.call(env) - return response unless html_response?(headers) return response if policy_present?(headers) if policy = request.content_security_policy @@ -31,12 +30,6 @@ def call(env) end private - def html_response?(headers) - if content_type = headers[CONTENT_TYPE] - /html/.match?(content_type) - end - end - def header_name(request) if request.content_security_policy_report_only POLICY_REPORT_ONLY
actionpack/test/dispatch/content_security_policy_test.rb+15 −0 modified@@ -395,6 +395,11 @@ class PolicyController < ActionController::Base content_security_policy_report_only only: :report_only + content_security_policy only: :api do |p| + p.default_src :none + p.frame_ancestors :none + end + def index head :ok end @@ -423,6 +428,10 @@ def no_policy head :ok end + def api + render json: {} + end + private def condition? params[:condition] == "true" @@ -439,6 +448,7 @@ def condition? get "/script-src", to: "policy#script_src" get "/style-src", to: "policy#style_src" get "/no-policy", to: "policy#no_policy" + get "/api", to: "policy#api" end end @@ -510,6 +520,11 @@ def test_generates_no_content_security_policy assert_nil response.headers["Content-Security-Policy-Report-Only"] end + def test_generates_api_security_policy + get "/api" + assert_policy "default-src 'none'; frame-ancestors 'none'" + end + private def assert_policy(expected, report_only: false) assert_response :success
d2253115ac2bMerge pull request #44635 from imtayadeway/tjw/api-csp-i
3 files changed · +19 −9
actionpack/CHANGELOG.md+4 −1 modified@@ -1,8 +1,11 @@ +* Allow Content Security Policy DSL to generate for API responses. + + *Tim Wade* + ## Rails 5.2.7 (March 10, 2022) ## * No changes. - ## Rails 5.2.6.3 (March 08, 2022) ## * No changes.
actionpack/lib/action_dispatch/http/content_security_policy.rb+0 −8 modified@@ -17,7 +17,6 @@ def call(env) request = ActionDispatch::Request.new env _, headers, _ = response = @app.call(env) - return response unless html_response?(headers) return response if policy_present?(headers) if policy = request.content_security_policy @@ -30,13 +29,6 @@ def call(env) end private - - def html_response?(headers) - if content_type = headers[CONTENT_TYPE] - content_type =~ /html/ - end - end - def header_name(request) if request.content_security_policy_report_only POLICY_REPORT_ONLY
actionpack/test/dispatch/content_security_policy_test.rb+15 −0 modified@@ -343,6 +343,11 @@ class PolicyController < ActionController::Base content_security_policy_report_only only: :report_only + content_security_policy only: :api do |p| + p.default_src :none + p.frame_ancestors :none + end + def index head :ok end @@ -367,6 +372,10 @@ def no_policy head :ok end + def api + render json: {} + end + private def condition? params[:condition] == "true" @@ -382,6 +391,7 @@ def condition? get "/report-only", to: "policy#report_only" get "/script-src", to: "policy#script_src" get "/no-policy", to: "policy#no_policy" + get "/api", to: "policy#api" end end @@ -448,6 +458,11 @@ def test_generates_no_content_security_policy assert_nil response.headers["Content-Security-Policy-Report-Only"] end + def test_generates_api_security_policy + get "/api" + assert_policy "default-src 'none'; frame-ancestors 'none'" + end + private def assert_policy(expected, report_only: false)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
15- github.com/advisories/GHSA-mm33-5vfq-3mm3ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-22577ghsaADVISORY
- www.debian.org/security/2023/dsa-5372ghsavendor-advisoryWEB
- discuss.rubyonrails.org/t/cve-2022-22577-possible-xss-vulnerability-in-action-pack/80533ghsaWEB
- github.com/rails/rails/commit/2b820a2a69fa50cffa74b4aedc57bf92ed6910ecghsaWEB
- github.com/rails/rails/commit/5299b57d596ea274f77f5ffee2b79c6ee0255508ghsaWEB
- github.com/rails/rails/commit/8198d7c4accad0b6ba956b9d59528534a289866bghsaWEB
- github.com/rails/rails/commit/d2253115ac2b30f5f7210670af906cebf79cf809ghsaWEB
- github.com/rails/rails/pull/44635ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/actionpack/CVE-2022-22577.ymlghsaWEB
- groups.google.com/g/ruby-security-ann/c/NuFRKaN5swIghsaWEB
- lists.debian.org/debian-lts-announce/2022/09/msg00002.htmlghsamailing-listWEB
- rubyonrails.org/2022/4/26/Rails-7-0-2-4-6-1-5-1-6-0-4-8-and-5-2-7-1-have-been-releasedghsaWEB
- security.netapp.com/advisory/ntap-20221118-0002ghsaWEB
- security.netapp.com/advisory/ntap-20221118-0002/mitre
News mentions
0No linked articles in our index yet.