Skip to content

Commit 9a4ff52

Browse files
committed
Sanitize markdown output in edit history and TOC edit views
The edit history view and TOC edit partial render Markdown content via to_html without passing through sanitize_content(), unlike the normal page view. This allows stored XSS via img onerror payloads for anyone who can view the edit history of a page with injected content. Apply sanitize_content() consistently to all to_html output, matching the existing safe pattern in leafables/show.html.erb.
1 parent e467ac8 commit 9a4ff52

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

app/views/leaves/_edit.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<%= link_to leafable_path(leaf), class: "toc__thumbnail", data: { turbo_frame: "_top" } do %>
88
<%= leaf.section.body if leaf.section? %>
9-
<%= leaf.leafable.body.to_html if leaf.page? %>
9+
<%= sanitize_content(leaf.leafable.body.to_html) if leaf.page? %>
1010
<%= image_tag leaf.leafable.image.variant(:large) if leaf.picture&.image&.attached? %>
1111
<% end %>
1212

app/views/pages/edits/show.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<% end %>
5252
</header>
5353

54-
<%= @edit.page.body.to_html %>
54+
<%= sanitize_content(@edit.page.body.to_html) %>
5555
<% end %>
5656
</section>
5757

@@ -62,6 +62,6 @@
6262
<% end %>
6363
</header>
6464

65-
<%= @leaf.page.body.to_html %>
65+
<%= sanitize_content(@leaf.page.body.to_html) %>
6666
</section>
6767
</div>

test/controllers/pages/edits_controller_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,25 @@ class Pages::EditsControllerTest < ActionDispatch::IntegrationTest
2323
assert_response :success
2424
assert_select "p", /such a great handbook/
2525
end
26+
27+
test "show sanitizes dangerous content in previous version" do
28+
leaf = books(:handbook).press Page.new(body: %(<img src=x onerror="alert(1)">)), title: "XSS Test"
29+
leaf.edit leafable_params: { body: "Clean content now" }
30+
31+
get page_edit_url(leaf, leaf.edits.last)
32+
33+
assert_response :success
34+
assert_match '<img src="x">', response.body
35+
assert_no_match(/onerror/, response.body)
36+
end
37+
38+
test "show sanitizes dangerous content in current version" do
39+
leaves(:welcome_page).edit leafable_params: { body: %(<img src=x onerror="alert(1)">) }
40+
41+
get page_edit_url(leaves(:welcome_page), leaves(:welcome_page).edits.last)
42+
43+
assert_response :success
44+
assert_match '<img src="x">', response.body
45+
assert_no_match(/onerror/, response.body)
46+
end
2647
end

0 commit comments

Comments
 (0)