Skip to content

Commit 945ae9a

Browse files
justin808claude
andauthored
Sanitize comment markdown on the ReScript page (#877)
Comments on /rescript rendered marked output directly, so HTML in a comment could run script in another visitor's browser. The React and server component views already sanitize. Pass the output through sanitize-html with the same defaults as Comment.jsx, and add a system spec that fails without the fix. Security: this closes a stored XSS on /rescript. Stored comments are unchanged; they are sanitized when displayed. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent af62fed commit 945ae9a

3 files changed

Lines changed: 19 additions & 1 deletion

File tree

‎client/app/bundles/comments/rescript/CommentList/Comment/Comment.res‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
@react.component
22
let make = (~comment: Actions.Fetch.t, ~cssTransitionGroupClassNames) => {
33
let rawMarkup = Marked.marked(comment.text, {gfm: true})
4-
let innerHTML = {"__html": rawMarkup}
4+
let sanitizedRawMarkup = SanitizeHtml.sanitize(rawMarkup)
5+
let innerHTML = {"__html": sanitizedRawMarkup}
56
let nodeRef = React.useRef(Js.Nullable.null)
67

78
// The 500 must correspond to the 0.5s in:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@module("sanitize-html") external sanitize: string => string = "default"

‎spec/rescript/rescript_spec.rb‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@
2929
end
3030
end
3131

32+
describe "comment markdown rendering" do
33+
before do
34+
Comment.create!(
35+
author: "Author",
36+
text: '**bold** <img src="missing.png" onerror="window.xssRan = true"><script>window.xssRan = true</script>'
37+
)
38+
visit "/rescript"
39+
end
40+
41+
it "keeps markdown formatting and removes unsafe HTML" do
42+
expect(page).to have_css(".js-comment-text strong", text: "bold")
43+
expect(page).to have_no_css(".js-comment-text img", visible: :all)
44+
expect(page).to have_no_css(".js-comment-text script", visible: :all)
45+
end
46+
end
47+
3248
describe "form submission functions" do
3349
let(:comment) { Comment.new(author: "Author", text: "This is a comment") }
3450
let(:author_field) { "comment_author" }

0 commit comments

Comments
 (0)