Moderate severityNVD Advisory· Published Dec 7, 2013· Updated Apr 29, 2026
CVE-2013-4492
CVE-2013-4492
Description
Cross-site scripting (XSS) vulnerability in exceptions.rb in the i18n gem before 0.6.6 for Ruby allows remote attackers to inject arbitrary web script or HTML via a crafted I18n::MissingTranslationData.new call.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
i18nRubyGems | < 0.6.6 | 0.6.6 |
Affected products
1Patches
292b57b1e4f84The I18n::MissingTranslation exception escapes key names for its html_message
2 files changed · +32 −6
lib/i18n/exceptions.rb+25 −3 modified@@ -1,3 +1,5 @@ +require 'cgi' + module I18n # Handles exceptions raised in the backend. All exceptions except for # MissingTranslationData exceptions are re-thrown. When a MissingTranslationData @@ -7,7 +9,19 @@ class ExceptionHandler include Module.new { def call(exception, locale, key, options) if exception.is_a?(MissingTranslation) - options[:rescue_format] == :html ? exception.html_message : exception.message + # + # TODO: this block is to be replaced by `exception.message` when + # rescue_format is removed + if options[:rescue_format] == :html + if @rescue_format_deprecation + $stderr.puts "[DEPRECATED] I18n's :recue_format option will be removed from a future release. All exception messages will be plain text. If you need the exception handler to return an html format please set or pass a custom exception handler." + @rescue_format_deprecation = true + end + exception.html_message + else + exception.message + end + elsif exception.is_a?(Exception) raise exception else @@ -45,8 +59,9 @@ def initialize(locale, key, options = nil) end def html_message - key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize } - %(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>) + key = CGI.escape_html titleize(keys.last) + path = CGI.escape_html keys.join('.') + %(<span class="translation_missing" title="translation missing: #{path}">#{key}</span>) end def keys @@ -63,6 +78,13 @@ def message def to_exception MissingTranslationData.new(locale, key, options) end + + protected + + # TODO : remove when #html_message is removed + def titleize(key) + key.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize } + end end include Base
test/i18n/exceptions_test.rb+7 −3 modified@@ -28,9 +28,13 @@ def test_invalid_locale_stores_locale end test "MissingTranslationData html_message is a span with the titlelized last key token" do - force_missing_translation_data do |exception| - assert_equal '<span class="translation_missing" title="translation missing: de.bar.foo">Foo</span>', exception.html_message - end + exception = I18n::MissingTranslationData.new(:de, :foo, :scope => :bar) + assert_equal '<span class="translation_missing" title="translation missing: de.bar.foo">Foo</span>', exception.html_message + end + + test "MissingTranslationData html_message html escapes key names" do + exception = I18n::MissingTranslationData.new(:de, '<script>Evil</script>', :scope => '<iframe src="example.com" />') + assert_equal '<span class="translation_missing" title="translation missing: de.<iframe src="example.com" />.<script>Evil</script>"><Script>Evil</Script></span>', exception.html_message end test "ExceptionHandler returns the html_message if :rescue_format => :html was given" do
92b57b1e4f84The I18n::MissingTranslation exception escapes key names for its html_message
2 files changed · +32 −6
lib/i18n/exceptions.rb+25 −3 modified@@ -1,3 +1,5 @@ +require 'cgi' + module I18n # Handles exceptions raised in the backend. All exceptions except for # MissingTranslationData exceptions are re-thrown. When a MissingTranslationData @@ -7,7 +9,19 @@ class ExceptionHandler include Module.new { def call(exception, locale, key, options) if exception.is_a?(MissingTranslation) - options[:rescue_format] == :html ? exception.html_message : exception.message + # + # TODO: this block is to be replaced by `exception.message` when + # rescue_format is removed + if options[:rescue_format] == :html + if @rescue_format_deprecation + $stderr.puts "[DEPRECATED] I18n's :recue_format option will be removed from a future release. All exception messages will be plain text. If you need the exception handler to return an html format please set or pass a custom exception handler." + @rescue_format_deprecation = true + end + exception.html_message + else + exception.message + end + elsif exception.is_a?(Exception) raise exception else @@ -45,8 +59,9 @@ def initialize(locale, key, options = nil) end def html_message - key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize } - %(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>) + key = CGI.escape_html titleize(keys.last) + path = CGI.escape_html keys.join('.') + %(<span class="translation_missing" title="translation missing: #{path}">#{key}</span>) end def keys @@ -63,6 +78,13 @@ def message def to_exception MissingTranslationData.new(locale, key, options) end + + protected + + # TODO : remove when #html_message is removed + def titleize(key) + key.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize } + end end include Base
test/i18n/exceptions_test.rb+7 −3 modified@@ -28,9 +28,13 @@ def test_invalid_locale_stores_locale end test "MissingTranslationData html_message is a span with the titlelized last key token" do - force_missing_translation_data do |exception| - assert_equal '<span class="translation_missing" title="translation missing: de.bar.foo">Foo</span>', exception.html_message - end + exception = I18n::MissingTranslationData.new(:de, :foo, :scope => :bar) + assert_equal '<span class="translation_missing" title="translation missing: de.bar.foo">Foo</span>', exception.html_message + end + + test "MissingTranslationData html_message html escapes key names" do + exception = I18n::MissingTranslationData.new(:de, '<script>Evil</script>', :scope => '<iframe src="example.com" />') + assert_equal '<span class="translation_missing" title="translation missing: de.<iframe src="example.com" />.<script>Evil</script>"><Script>Evil</Script></span>', exception.html_message end test "ExceptionHandler returns the html_message if :rescue_format => :html was given" do
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
19- weblog.rubyonrails.org/2013/12/3/Rails_3_2_16_and_4_0_2_have_been_released/nvdPatchVendor Advisory
- github.com/advisories/GHSA-r5hc-9xx5-97rwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2013-4492ghsaADVISORY
- lists.opensuse.org/opensuse-updates/2013-12/msg00093.htmlnvdWEB
- weblog.rubyonrails.org/2013/12/3/Rails_3_2_16_and_4_0_2_have_been_releasedghsaWEB
- www.debian.org/security/2013/dsa-2830nvdWEB
- access.redhat.com/errata/RHBA-2015:1100ghsaWEB
- access.redhat.com/errata/RHSA-2017:0320ghsaWEB
- access.redhat.com/errata/RHSA-2018:0380ghsaWEB
- access.redhat.com/security/cve/CVE-2013-4492ghsaWEB
- bugzilla.redhat.com/show_bug.cgighsaWEB
- github.com/ruby-i18n/i18n/commit/92b57b1e4f84adcdcc3a375278f299274be62445ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/i18n/CVE-2013-4492.ymlghsaWEB
- github.com/svenfuchs/i18n/commit/92b57b1e4f84adcdcc3a375278f299274be62445nvdWEB
- groups.google.com/forum/ghsaWEB
- web.archive.org/web/20201208125214/https://groups.google.com/forum/message/rawghsaWEB
- web.archive.org/web/20210731082547/http://www.securityfocus.com/bid/64076ghsaWEB
- www.securityfocus.com/bid/64076nvd
- groups.google.com/forum/message/rawnvd
News mentions
0No linked articles in our index yet.