From 20c01f234cacf3046cbd8dfba521ec4a078bcebe Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Fri, 9 Oct 2026 13:58:00 +0900 Subject: [PATCH 4/4] Stop escaping the attributes of the HTML tags allowed in Textile because unsafe attributes are now removed by the sanitizer --- .../wiki_formatting/textile/redcloth3.rb | 2 +- .../wiki_formatting/textile_formatter_test.rb | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/redmine/wiki_formatting/textile/redcloth3.rb b/lib/redmine/wiki_formatting/textile/redcloth3.rb index e7f949a95..c62b81c9d 100644 --- a/lib/redmine/wiki_formatting/textile/redcloth3.rb +++ b/lib/redmine/wiki_formatting/textile/redcloth3.rb @@ -1216,7 +1216,7 @@ class RedCloth3 < String all, tag, close = $1, $2, $3 if close.present? && (ALLOWED_TAGS.include?(tag) || (tag =~ /\Aredpre#\d+\z/)) - "<#{htmlesc all}#{close}" + "<#{all}#{close}" else "<#{htmlesc all}#{'>' unless close.blank?}" end diff --git a/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb b/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb index c8d1c26e6..bd5280584 100644 --- a/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb @@ -859,6 +859,45 @@ class Redmine::WikiFormatting::TextileFormatterTest < Redmine::HelperTest assert_includes to_html(%{version:"foo "}), %{version:"foo <bar>"} end + def test_should_keep_quoted_attributes_of_allowed_tags + with_allowed_tags('font', 'a') do + assert_html_output( + { + %{text} => 'text', + 'text' => + '

text

', + }, + false + ) + end + end + + def test_should_remove_unsafe_attributes_from_allowed_tags + with_allowed_tags('font', 'a') do + assert_html_output( + { + 'text' => '

text

', + 'text' => '

text

', + 'text' => '

text

', + 'text' => 'text', + }, + false + ) + end + end + + def test_should_escape_tags_not_in_allowed_tags + with_allowed_tags('font') do + assert_html_output('text' => '<a href="/foo">text</a>') + end + end + + def test_should_remove_allowed_tags_not_accepted_by_sanitizer + with_allowed_tags('iframe') do + assert_html_output({'text' => 'text'}, false) + end + end + def test_nested_notextile_tag_boundaries ["<div class=foo >", "<div class=foo >"].each do |payload| @@ -873,6 +912,15 @@ class Redmine::WikiFormatting::TextileFormatterTest < Redmine::HelperTest private + def with_allowed_tags(*tags) + allowed_tags = Redmine::WikiFormatting::Textile::Filter::ALLOWED_TAGS + original_tags = allowed_tags.dup + allowed_tags.concat(tags) + yield + ensure + allowed_tags.replace(original_tags) + end + def assert_html_output(to_test, expect_paragraph = true) to_test.each do |text, expected| assert_equal( -- 2.55.0