Possible XSS vulnerability in ActionView
Description
In ActionView before versions 6.0.2.2 and 5.2.4.2, there is a possible XSS vulnerability in ActionView's JavaScript literal escape helpers. Views that use the j or escape_javascript methods may be susceptible to XSS attacks. The issue is fixed in versions 6.0.2.2 and 5.2.4.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
ActionView's JavaScript literal escape helpers (`j`, `escape_javascript`) are vulnerable to XSS when used inside template literals (`${...}` or backticks).
Vulnerability
CVE-2020-5267 is an XSS vulnerability in Ruby on Rails' ActionView, affecting the j and escape_javascript helper methods. These methods are designed to escape input for JavaScript string literals, but they did not escape the backtick (` `) character or the dollar sign ($`) in the context of ES6 template literals [2][4]. An attacker can break out of the intended string literal and inject arbitrary JavaScript code.
Exploitation
The attack surface is any view that passes user-controlled input through j or escape_javascript inside a template literal (backtick-quoted string) in a ` An attacker supplying a payload containing ` and ${...} sequences can craft a malicious string that closes the template literal and executes attacker-controlled code. No authentication is required if the input originates from an untrusted source (e.g., request parameters, user-generated content) [1][2]. ## Impact Successful exploitation allows an attacker to perform cross-site scripting (XSS) attacks. The attacker can execute arbitrary JavaScript in the victim's browser context, potentially leading to session theft, credential harvesting, or unauthorized actions. The CVSS metrics (not fully assessed by NVD as of the reference) indicate a high severity due to the lack of proper input sanitization [1]. ## Mitigation The vulnerability is patched in Rails versions 5.2.4.2 and 6.0.2.2. Users on unsupported versions should upgrade immediately. For those unable to upgrade immediately, a monkey patch is provided that explicitly escapes backtick and dollar sign characters in the JS_ESCAPE_MAP` and updates the escaping regex [2][4]. No workarounds are available for versions earlier than 5.2.
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 |
|---|---|---|
actionviewRubyGems | < 5.2.4.2 | 5.2.4.2 |
actionviewRubyGems | >= 6.0.0, < 6.0.2.2 | 6.0.2.2 |
Affected products
19- ghsa-coords18 versionspkg:gem/actionviewpkg:rpm/opensuse/rmt-server&distro=openSUSE%20Leap%2015.1pkg:rpm/opensuse/rmt-server&distro=openSUSE%20Leap%2015.2pkg:rpm/opensuse/rubygem-actionview-5_1&distro=openSUSE%20Leap%2015.1pkg:rpm/opensuse/rubygem-actionview-6.0&distro=openSUSE%20Tumbleweedpkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015-ESPOSpkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015-LTSSpkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Public%20Cloud%2015%20SP1pkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Public%20Cloud%2015%20SP2pkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Server%20Applications%2015%20SP1pkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Server%20Applications%2015%20SP2pkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Server%2015-LTSSpkg:rpm/suse/rmt-server&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015pkg:rpm/suse/rubygem-actionview-4_2&distro=SUSE%20OpenStack%20Cloud%207pkg:rpm/suse/rubygem-actionview-4_2&distro=SUSE%20OpenStack%20Cloud%20Crowbar%208pkg:rpm/suse/rubygem-actionview-4_2&distro=SUSE%20OpenStack%20Cloud%20Crowbar%209pkg:rpm/suse/rubygem-actionview-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015pkg:rpm/suse/rubygem-actionview-5_1&distro=SUSE%20Linux%20Enterprise%20High%20Availability%20Extension%2015%20SP1
< 5.2.4.2+ 17 more
- (no CPE)range: < 5.2.4.2
- (no CPE)range: < 2.6.5-lp151.2.18.2
- (no CPE)range: < 2.6.5-lp152.2.3.1
- (no CPE)range: < 5.1.4-lp151.3.3.1
- (no CPE)range: < 6.0.4.4-1.1
- (no CPE)range: < 2.6.5-3.34.1
- (no CPE)range: < 2.6.5-3.34.1
- (no CPE)range: < 2.6.5-3.18.1
- (no CPE)range: < 2.6.5-3.3.1
- (no CPE)range: < 2.6.5-3.18.1
- (no CPE)range: < 2.6.5-3.3.1
- (no CPE)range: < 2.6.5-3.34.1
- (no CPE)range: < 2.6.5-3.34.1
- (no CPE)range: < 4.2.9-9.6.1
- (no CPE)range: < 4.2.9-9.6.1
- (no CPE)range: < 4.2.9-9.6.1
- (no CPE)range: < 5.1.4-3.3.1
- (no CPE)range: < 5.1.4-3.3.1
- rails/actionviewv5Range: < 5.2.4.2
Patches
3157920aead96Preparing for 6.0.2.2 release
17 files changed · +17 −17
actioncable/lib/action_cable/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actioncable/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@rails/actioncable", - "version": "6.0.2-1", + "version": "6.0.2-2", "description": "WebSocket framework for Ruby on Rails.", "main": "app/assets/javascripts/action_cable.js", "files": [
actionmailbox/lib/action_mailbox/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionmailer/lib/action_mailer/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionpack/lib/action_pack/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actiontext/lib/action_text/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actiontext/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@rails/actiontext", - "version": "6.0.2-1", + "version": "6.0.2-2", "description": "Edit and display rich text in Rails applications", "main": "app/javascript/actiontext/index.js", "files": [
actionview/lib/action_view/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionview/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@rails/ujs", - "version": "6.0.2-1", + "version": "6.0.2-2", "description": "Ruby on Rails unobtrusive scripting adapter", "main": "lib/assets/compiled/rails-ujs.js", "files": [
activejob/lib/active_job/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activemodel/lib/active_model/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activerecord/lib/active_record/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activestorage/lib/active_storage/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activestorage/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@rails/activestorage", - "version": "6.0.2-1", + "version": "6.0.2-2", "description": "Attach cloud and local files in Rails applications", "main": "app/assets/javascripts/activestorage.js", "files": [
activesupport/lib/active_support/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
railties/lib/rails/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 6 MINOR = 0 TINY = 2 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
16 files changed · +51 −51
actioncable/lib/action_cable/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actioncable/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "actioncable", - "version": "5.2.4-1", + "version": "5.2.4-2", "description": "WebSocket framework for Ruby on Rails.", "main": "lib/assets/compiled/action_cable.js", "files": [
actionmailer/lib/action_mailer/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionpack/lib/action_pack/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionview/lib/action_view/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
actionview/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "rails-ujs", - "version": "5.2.4-1", + "version": "5.2.4-2", "description": "Ruby on Rails unobtrusive scripting adapter", "main": "lib/assets/compiled/rails-ujs.js", "files": [
activejob/lib/active_job/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activemodel/lib/active_model/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activerecord/lib/active_record/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activestorage/lib/active_storage/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
activestorage/package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "activestorage", - "version": "5.2.4-1", + "version": "5.2.4-2", "description": "Attach cloud and local files in Rails applications", "main": "app/assets/javascripts/activestorage.js", "files": [
activesupport/lib/active_support/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
Gemfile.lock+36 −36 modified@@ -26,63 +26,63 @@ GIT PATH remote: . specs: - actioncable (5.2.4.1) - actionpack (= 5.2.4.1) + actioncable (5.2.4.2) + actionpack (= 5.2.4.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.4.1) - actionpack (= 5.2.4.1) - actionview (= 5.2.4.1) - activejob (= 5.2.4.1) + actionmailer (5.2.4.2) + actionpack (= 5.2.4.2) + actionview (= 5.2.4.2) + activejob (= 5.2.4.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.4.1) - actionview (= 5.2.4.1) - activesupport (= 5.2.4.1) + actionpack (5.2.4.2) + actionview (= 5.2.4.2) + activesupport (= 5.2.4.2) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.4.1) - activesupport (= 5.2.4.1) + actionview (5.2.4.2) + activesupport (= 5.2.4.2) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.4.1) - activesupport (= 5.2.4.1) + activejob (5.2.4.2) + activesupport (= 5.2.4.2) globalid (>= 0.3.6) - activemodel (5.2.4.1) - activesupport (= 5.2.4.1) - activerecord (5.2.4.1) - activemodel (= 5.2.4.1) - activesupport (= 5.2.4.1) + activemodel (5.2.4.2) + activesupport (= 5.2.4.2) + activerecord (5.2.4.2) + activemodel (= 5.2.4.2) + activesupport (= 5.2.4.2) arel (>= 9.0) - activestorage (5.2.4.1) - actionpack (= 5.2.4.1) - activerecord (= 5.2.4.1) + activestorage (5.2.4.2) + actionpack (= 5.2.4.2) + activerecord (= 5.2.4.2) marcel (~> 0.3.1) - activesupport (5.2.4.1) + activesupport (5.2.4.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - rails (5.2.4.1) - actioncable (= 5.2.4.1) - actionmailer (= 5.2.4.1) - actionpack (= 5.2.4.1) - actionview (= 5.2.4.1) - activejob (= 5.2.4.1) - activemodel (= 5.2.4.1) - activerecord (= 5.2.4.1) - activestorage (= 5.2.4.1) - activesupport (= 5.2.4.1) + rails (5.2.4.2) + actioncable (= 5.2.4.2) + actionmailer (= 5.2.4.2) + actionpack (= 5.2.4.2) + actionview (= 5.2.4.2) + activejob (= 5.2.4.2) + activemodel (= 5.2.4.2) + activerecord (= 5.2.4.2) + activestorage (= 5.2.4.2) + activesupport (= 5.2.4.2) bundler (>= 1.3.0) - railties (= 5.2.4.1) + railties (= 5.2.4.2) sprockets-rails (>= 2.0.0) - railties (5.2.4.1) - actionpack (= 5.2.4.1) - activesupport (= 5.2.4.1) + railties (5.2.4.2) + actionpack (= 5.2.4.2) + activesupport (= 5.2.4.2) method_source rake (>= 0.8.7) thor (>= 0.19.0, < 2.0)
RAILS_VERSION+1 −1 modified@@ -1 +1 @@ -5.2.4.1 +5.2.4.2
railties/lib/rails/gem_version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
version.rb+1 −1 modified@@ -10,7 +10,7 @@ module VERSION MAJOR = 5 MINOR = 2 TINY = 4 - PRE = "1" + PRE = "2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end
033a738817abFix possible XSS vector in JS escape helper
2 files changed · +12 −2
actionview/lib/action_view/helpers/javascript_helper.rb+4 −2 modified@@ -12,7 +12,9 @@ module JavaScriptHelper "\n" => '\n', "\r" => '\n', '"' => '\\"', - "'" => "\\'" + "'" => "\\'", + "`" => "\\`", + "$" => "\\$" } JS_ESCAPE_MAP[(+"\342\200\250").force_encoding(Encoding::UTF_8).encode!] = "
" @@ -29,7 +31,7 @@ def escape_javascript(javascript) if javascript.empty? result = "" else - result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u, JS_ESCAPE_MAP) + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP) end javascript.html_safe? ? result.html_safe : result end
actionview/test/template/javascript_helper_test.rb+8 −0 modified@@ -36,6 +36,14 @@ def test_escape_javascript assert_equal %(dont <\\/close> tags), j(%(dont </close> tags)) end + def test_escape_backtick + assert_equal "\\`", escape_javascript("`") + end + + def test_escape_dollar_sign + assert_equal "\\$", escape_javascript("$") + end + def test_escape_javascript_with_safebuffer given = %('quoted' "double-quoted" new-line:\n </closed>) expect = %(\\'quoted\\' \\"double-quoted\\" new-line:\\n <\\/closed>)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- lists.opensuse.org/opensuse-security-announce/2020-05/msg00019.htmlghsavendor-advisoryx_refsource_SUSEWEB
- github.com/advisories/GHSA-65cv-r6x7-79hvghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XJ7NUWXAEVRQCROIIBV4C6WXO6IR3KSB/mitrevendor-advisoryx_refsource_FEDORA
- nvd.nist.gov/vuln/detail/CVE-2020-5267ghsaADVISORY
- www.openwall.com/lists/oss-security/2020/03/19/1ghsamailing-listx_refsource_MLISTWEB
- github.com/rails/rails/commit/033a738817abd6e446e1b320cb7d1a5c15224e9aghsax_refsource_MISCWEB
- github.com/rails/rails/security/advisories/GHSA-65cv-r6x7-79hvghsax_refsource_CONFIRMWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/actionview/CVE-2020-5267.ymlghsaWEB
- groups.google.com/forum/ghsaWEB
- lists.debian.org/debian-lts-announce/2020/03/msg00022.htmlghsamailing-listx_refsource_MLISTWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XJ7NUWXAEVRQCROIIBV4C6WXO6IR3KSBghsaWEB
News mentions
0No linked articles in our index yet.