Medium severity4.0NVD Advisory· Published Jan 9, 2025· Updated Apr 15, 2026
CVE-2023-28362
CVE-2023-28362
Description
The redirect_to method in Rails allows provided values to contain characters which are not legal in an HTTP header value. This results in the potential for downstream services which enforce RFC compliance on HTTP response headers to remove the assigned Location header.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
actionpackRubyGems | < 6.1.7.4 | 6.1.7.4 |
actionpackRubyGems | >= 7.0.0, < 7.0.5.1 | 7.0.5.1 |
Patches
369e37c84e3f7Added check for illegal HTTP header value in redirect_to
2 files changed · +36 −1
actionpack/lib/action_controller/metal/redirecting.rb+18 −1 modified@@ -9,6 +9,8 @@ module Redirecting class UnsafeRedirectError < StandardError; end + ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze + included do mattr_accessor :raise_on_open_redirects, default: false end @@ -86,7 +88,11 @@ def redirect_to(options = {}, response_options = {}) allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host } self.status = _extract_redirect_to_status(options, response_options) - self.location = _enforce_open_redirect_protection(_compute_redirect_to_location(request, options), allow_other_host: allow_other_host) + + redirect_to_location = _compute_redirect_to_location(request, options) + _ensure_url_is_http_header_safe(redirect_to_location) + + self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host) self.response_body = "" end @@ -204,5 +210,16 @@ def _url_host_allowed?(url) rescue ArgumentError, URI::Error false end + + def _ensure_url_is_http_header_safe(url) + # Attempt to comply with the set of valid token characters + # defined for an HTTP header value in + # https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 + if url.match(ILLEGAL_HEADER_VALUE_REGEX) + msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + raise UnsafeRedirectError, msg + end + end end end
actionpack/test/controller/redirect_test.rb+18 −0 modified@@ -104,6 +104,10 @@ def unsafe_redirect_protocol_relative_triple_slash redirect_to "///www.rubyonrails.org/" end + def unsafe_redirect_with_illegal_http_header_value_character + redirect_to "javascript:alert(document.domain)\b", allow_other_host: true + end + def only_path_redirect redirect_to action: "other_host", only_path: true end @@ -556,6 +560,20 @@ def test_unsafe_redirect_with_protocol_relative_triple_slash_url end end + def test_unsafe_redirect_with_illegal_http_header_value_character + with_raise_on_open_redirects do + error = assert_raise(ActionController::Redirecting::UnsafeRedirectError) do + get :unsafe_redirect_with_illegal_http_header_value_character + end + + msg = "The redirect URL javascript:alert(document.domain)\b contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + + assert_equal msg, error.message + end + end + + def test_only_path_redirect with_raise_on_open_redirects do get :only_path_redirect
1c3f93d1e90aAdded check for illegal HTTP header value in redirect_to
2 files changed · +37 −1
actionpack/lib/action_controller/metal/redirecting.rb+20 −1 modified@@ -7,6 +7,10 @@ module Redirecting include AbstractController::Logger include ActionController::UrlFor + ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze + + class UnsafeRedirectError < StandardError; end + # Redirects the browser to the target specified in +options+. This parameter can be any one of: # # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+. @@ -60,7 +64,11 @@ def redirect_to(options = {}, response_options = {}) raise AbstractController::DoubleRenderError if response_body self.status = _extract_redirect_to_status(options, response_options) - self.location = _compute_redirect_to_location(request, options) + + redirect_to_location = _compute_redirect_to_location(request, options) + _ensure_url_is_http_header_safe(redirect_to_location) + + self.location = redirect_to_location self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>" end @@ -129,5 +137,16 @@ def _url_host_allowed?(url) rescue ArgumentError, URI::Error false end + + def _ensure_url_is_http_header_safe(url) + # Attempt to comply with the set of valid token characters + # defined for an HTTP header value in + # https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 + if url.match(ILLEGAL_HEADER_VALUE_REGEX) + msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + raise UnsafeRedirectError, msg + end + end end end
actionpack/test/controller/redirect_test.rb+17 −0 modified@@ -153,6 +153,11 @@ def redirect_with_null_bytes redirect_to "\000/lol\r\nwat" end + def unsafe_redirect_with_illegal_http_header_value_character + redirect_to "javascript:alert(document.domain)\b" + end + + def rescue_errors(e) raise e end private @@ -437,6 +442,18 @@ def test_redirect_to_with_block_and_accepted_options assert_redirected_to "http://test.host/redirect/hello_world" end end + + def test_unsafe_redirect_with_illegal_http_header_value_character + error = assert_raise(ActionController::Redirecting::UnsafeRedirectError) do + get :unsafe_redirect_with_illegal_http_header_value_character + end + + msg = "The redirect URL javascript:alert(document.domain)\b contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + + assert_equal msg, error.message + end + end module ModuleTest
c9ab9b32bcdcAdded check for illegal HTTP header value in redirect_to
2 files changed · +35 −1
actionpack/lib/action_controller/metal/redirecting.rb+18 −1 modified@@ -4,6 +4,8 @@ module ActionController module Redirecting extend ActiveSupport::Concern + ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze + include AbstractController::Logger include ActionController::UrlFor @@ -86,7 +88,11 @@ def redirect_to(options = {}, response_options = {}) allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host } self.status = _extract_redirect_to_status(options, response_options) - self.location = _enforce_open_redirect_protection(_compute_redirect_to_location(request, options), allow_other_host: allow_other_host) + + redirect_to_location = _compute_redirect_to_location(request, options) + _ensure_url_is_http_header_safe(redirect_to_location) + + self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host) self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>" end @@ -204,5 +210,16 @@ def _url_host_allowed?(url) rescue ArgumentError, URI::Error false end + + def _ensure_url_is_http_header_safe(url) + # Attempt to comply with the set of valid token characters + # defined for an HTTP header value in + # https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 + if url.match(ILLEGAL_HEADER_VALUE_REGEX) + msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + raise UnsafeRedirectError, msg + end + end end end
actionpack/test/controller/redirect_test.rb+17 −0 modified@@ -104,6 +104,10 @@ def unsafe_redirect_protocol_relative_triple_slash redirect_to "///www.rubyonrails.org/" end + def unsafe_redirect_with_illegal_http_header_value_character + redirect_to "javascript:alert(document.domain)\b", allow_other_host: true + end + def only_path_redirect redirect_to action: "other_host", only_path: true end @@ -556,6 +560,19 @@ def test_unsafe_redirect_with_protocol_relative_triple_slash_url end end + def test_unsafe_redirect_with_illegal_http_header_value_character + with_raise_on_open_redirects do + error = assert_raise(ActionController::Redirecting::UnsafeRedirectError) do + get :unsafe_redirect_with_illegal_http_header_value_character + end + + msg = "The redirect URL javascript:alert(document.domain)\b contains one or more illegal HTTP header field character. " \ + "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" + + assert_equal msg, error.message + end + end + def test_only_path_redirect with_raise_on_open_redirects do get :only_path_redirect
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- github.com/advisories/GHSA-4g8v-vg43-wpgfnvdADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-28362ghsaADVISORY
- discuss.rubyonrails.org/t/cve-2023-28362-possible-xss-via-user-supplied-values-to-redirect-to/83132nvdWEB
- github.com/rails/rails/commit/1c3f93d1e90a3475f9ae2377ead25ccf11f71441nvdWEB
- github.com/rails/rails/commit/69e37c84e3f77d75566424c7d0015172d6a6fac5nvdWEB
- github.com/rails/rails/commit/c9ab9b32bcdcfd8bcd55907f6c7b20b4e004cc23ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/actionpack/CVE-2023-28362.ymlghsaWEB
- security.netapp.com/advisory/ntap-20250502-0009ghsaWEB
- security.netapp.com/advisory/ntap-20250502-0009/nvd
News mentions
0No linked articles in our index yet.