VYPR
Moderate severityNVD Advisory· Published Nov 28, 2011· Updated Apr 29, 2026

CVE-2011-4319

CVE-2011-4319

Description

Cross-site scripting (XSS) vulnerability in the i18n translations helper method in Ruby on Rails 3.0.x before 3.0.11 and 3.1.x before 3.1.2, and the rails_xss plugin in Ruby on Rails 2.3.x, allows remote attackers to inject arbitrary web script or HTML via vectors related to a translations string whose name ends with an "html" substring.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Cross-site scripting in Ruby on Rails (3.0.x < 3.0.11, 3.1.x < 3.1.2, and 2.3.x via rails_xss) due to improper HTML escaping of interpolated values in `translate` helper when translation name ends with "html".

Vulnerability

A cross-site scripting (XSS) vulnerability exists in the translate (aliased as t) helper method of Ruby on Rails 3.0.x before 3.0.11, 3.1.x before 3.1.2, and in the rails_xss plugin for the 2.3.x series [1][3][4]. When a translation string key ends with an "html" substring (e.g., foo_html), the helper marks the translation as HTML-safe. However, it failed to HTML-escape interpolated arguments before insertion, allowing a remote attacker to inject arbitrary web script or HTML via user-controlled values passed to the translate method [4].

Exploitation

An attacker must be able to supply input that is used as an interpolation argument to the translate (or t) helper call within a view template, where the translation key ends with _html [3][4]. No authentication is required if the application renders user input in such a translation call. The attacker provides a crafted string containing JavaScript or HTML as the interpolation value, e.g., ''. The translation method, prior to the fix, directly inserts this unescaped string into the HTML output [4].

Impact

Successful exploitation leads to stored or reflected cross-site scripting (XSS), depending on how the application stores or reflects the user input [1][3]. The attacker can execute arbitrary JavaScript in the context of the victim's browser session, potentially stealing session cookies, performing actions on behalf of the user, or defacing the page. The privilege level is that of the victim user; no server-side code execution is achieved.

Mitigation

The following versions contain the fix: Ruby on Rails 3.0.11, 3.1.2 (released November 18, 2011), and users of the 2.3.x series should upgrade to the rails_xss plugin version that includes the same fix [1][4]. For Rails 3.0.x and 3.1.x, upgrading to the patched minor release eliminates the vulnerability. No workaround is documented for older versions that cannot be upgraded. The vulnerability is not listed on the CISA Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 23, 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.

PackageAffected versionsPatched versions
actionpackRubyGems
>= 3.0.0, < 3.0.113.0.11
actionpackRubyGems
>= 3.1.0, < 3.1.23.1.2

Affected products

59
  • Rubyonrails/Rails56 versions
    cpe:2.3:a:rubyonrails:rails:2.3.10:*:*:*:*:*:*:*+ 55 more
    • cpe:2.3:a:rubyonrails:rails:2.3.10:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.11:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.12:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.2:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.3:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.4:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:2.3.9:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:beta:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:beta2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:beta3:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:beta4:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:rc:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.10:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.10:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.1:pre:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.2:pre:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.4:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.5:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.5:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.6:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.6:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.6:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.7:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.7:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.7:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.8:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.8:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.8:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.8:rc3:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.8:rc4:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:rc3:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:rc4:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.0.9:rc5:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:beta1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc3:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc4:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc5:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc6:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc7:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.0:rc8:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.1:rc1:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.1:rc2:*:*:*:*:*:*
    • cpe:2.3:a:rubyonrails:rails:3.1.1:rc3:*:*:*:*:*:*
    • (no CPE)
  • cpe:2.3:a:rubyonrails:ruby_on_rails:3.0.4:*:*:*:*:*:*:*+ 1 more
    • cpe:2.3:a:rubyonrails:ruby_on_rails:3.0.4:*:*:*:*:*:*:*
    • (no CPE)range: >=3.0.0 <3.0.11, >=3.1.0 <3.1.2
  • ghsa-coords
    Range: >= 3.0.0, < 3.0.11

Patches

2
ba2d85012088

_html translation should escape interpolated arguments

https://github.com/rails/railslestNov 17, 2011via ghsa
3 files changed · +29 4
  • actionpack/CHANGELOG+14 0 modified
    @@ -1,5 +1,19 @@
     *Rails 3.0.11 (unreleased)*
     
    +* Fix XSS security vulnerability in the `translate` helper method. When using interpolation
    +  in combination with HTML-safe translations, the interpolated input would not get HTML
    +  escaped. *GH 3664*
    +
    +  Before:
    +
    +      translate('foo_html', :something => '<script>') # => "...<script>..."
    +
    +  After:
    +
    +      translate('foo_html', :something => '<script>') # => "...&lt;script&gt;..."
    +
    +  *Sergey Nartimov*
    +
     * Implement a workaround for a bug in ruby-1.9.3p0 where an error would be
       raised while attempting to convert a template from one encoding to another.
     
    
  • actionpack/lib/action_view/helpers/translation_helper.rb+9 4 modified
    @@ -45,11 +45,16 @@ module TranslationHelper
           # you know what kind of output to expect when you call translate in a template.
           def translate(key, options = {})
             options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
    -        translation = I18n.translate(scope_key_by_partial(key), options)
    -        if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
    -          translation.html_safe
    +        if html_safe_translation_key?(key)
    +          html_safe_options = options.dup
    +          options.except(*I18n::RESERVED_KEYS).each do |name, value|
    +            html_safe_options[name] = ERB::Util.html_escape(value.to_s)
    +          end
    +          translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
    +
    +          translation.respond_to?(:html_safe) ? translation.html_safe : translation
             else
    -          translation
    +          I18n.translate(scope_key_by_partial(key), options)
             end
           end
           alias :t :translate
    
  • actionpack/test/template/translation_helper_test.rb+6 0 modified
    @@ -17,6 +17,7 @@ def setup
             :hello => '<a>Hello World</a>',
             :html => '<a>Hello World</a>',
             :hello_html => '<a>Hello World</a>',
    +        :interpolated_html => '<a>Hello %{word}</a>',
             :array_html => %w(foo bar),
             :array => %w(foo bar)
           }
    @@ -83,6 +84,11 @@ def test_translate_marks_translations_with_a_html_suffix_as_safe_html
         assert translate(:'translations.hello_html').html_safe?
       end
     
    +  def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
    +    assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>')
    +    assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>"))
    +  end
    +
       def test_translation_returning_an_array_ignores_html_suffix
         assert_equal ["foo", "bar"], translate(:'translations.array_html')
       end
    
2d5b105d4bcb

_html translation should escape interpolated arguments

https://github.com/rails/railslestNov 17, 2011via ghsa
3 files changed · +29 4
  • actionpack/CHANGELOG.md+14 0 modified
    @@ -1,5 +1,19 @@
     ## Rails 3.1.2 (unreleased) ##
     
    +*   Fix XSS security vulnerability in the `translate` helper method. When using interpolation
    +    in combination with HTML-safe translations, the interpolated input would not get HTML
    +    escaped. *GH 3664*
    +
    +    Before:
    +
    +        translate('foo_html', :something => '<script>') # => "...<script>..."
    +
    +    After:
    +
    +        translate('foo_html', :something => '<script>') # => "...&lt;script&gt;..."
    +
    +    *Sergey Nartimov*
    +
     *   Upgrade sprockets dependency to ~> 2.1.0
     
     *   Ensure that the format isn't applied twice to the cache key, else it becomes impossible
    
  • actionpack/lib/action_view/helpers/translation_helper.rb+9 4 modified
    @@ -45,11 +45,16 @@ module TranslationHelper
           # you know what kind of output to expect when you call translate in a template.
           def translate(key, options = {})
             options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
    -        translation = I18n.translate(scope_key_by_partial(key), options)
    -        if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
    -          translation.html_safe
    +        if html_safe_translation_key?(key)
    +          html_safe_options = options.dup
    +          options.except(*I18n::RESERVED_KEYS).each do |name, value|
    +            html_safe_options[name] = ERB::Util.html_escape(value.to_s)
    +          end
    +          translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
    +
    +          translation.respond_to?(:html_safe) ? translation.html_safe : translation
             else
    -          translation
    +          I18n.translate(scope_key_by_partial(key), options)
             end
           end
           alias :t :translate
    
  • actionpack/test/template/translation_helper_test.rb+6 0 modified
    @@ -17,6 +17,7 @@ def setup
             :hello => '<a>Hello World</a>',
             :html => '<a>Hello World</a>',
             :hello_html => '<a>Hello World</a>',
    +        :interpolated_html => '<a>Hello %{word}</a>',
             :array_html => %w(foo bar),
             :array => %w(foo bar)
           }
    @@ -83,6 +84,11 @@ def test_translate_marks_translations_with_a_html_suffix_as_safe_html
         assert translate(:'translations.hello_html').html_safe?
       end
     
    +  def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
    +    assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>')
    +    assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>"))
    +  end
    +
       def test_translation_returning_an_array_ignores_html_suffix
         assert_equal ["foo", "bar"], translate(:'translations.array_html')
       end
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

17

News mentions

0

No linked articles in our index yet.