Skip to content

Commit e663f08

Browse files
Merge pull request from GHSA-cfjv-5498-mph5
Prior to this commit, when a translation key indicated that the translation text was HTML, the value returned by `I18n.translate` would always be marked as `html_safe`. However, the value returned by `I18n.translate` could be an untrusted value directly from `options[:default]`. This commit ensures values directly from `options[:default]` are not marked as `html_safe`.
1 parent 5259062 commit e663f08

File tree

2 files changed

+15
-1
lines changed

2 files changed

+15
-1
lines changed

actionview/lib/action_view/helpers/translation_helper.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,13 @@ def translate(key, **options)
9696
end
9797
end
9898

99+
html_safe_options[:default] = MISSING_TRANSLATION unless html_safe_options[:default].blank?
100+
99101
translation = I18n.translate(fully_resolved_key, **html_safe_options.merge(raise: i18n_raise))
100102

101-
if translation.respond_to?(:map)
103+
if translation.equal?(MISSING_TRANSLATION)
104+
translated_text = options[:default].first
105+
elsif translation.respond_to?(:map)
102106
translated_text = translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
103107
else
104108
translated_text = translation.respond_to?(:html_safe) ? translation.html_safe : translation
@@ -150,6 +154,9 @@ def localize(object, **options)
150154
alias :l :localize
151155

152156
private
157+
MISSING_TRANSLATION = Object.new
158+
private_constant :MISSING_TRANSLATION
159+
153160
def scope_key_by_partial(key)
154161
stringified_key = key.to_s
155162
if stringified_key.start_with?(".")

actionview/test/template/translation_helper_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ def test_translate_with_last_default_not_named_html
247247
assert_equal false, translation.html_safe?
248248
end
249249

250+
def test_translate_does_not_mark_unsourced_string_default_as_html_safe
251+
untrusted_string = "<script>alert()</script>"
252+
translation = translate(:"translations.missing", default: [:"translations.missing_html", untrusted_string])
253+
assert_equal untrusted_string, translation
254+
assert_not_predicate translation, :html_safe?
255+
end
256+
250257
def test_translate_with_string_default
251258
translation = translate(:'translations.missing', default: "A Generic String")
252259
assert_equal "A Generic String", translation

0 commit comments

Comments
 (0)