From 04fb62a6f58688c6322f7d65d06e8f3a0e4ceb76 Mon Sep 17 00:00:00 2001 From: Kim Emmanuel <41296331+kimesf@users.noreply.github.com> Date: Thu, 7 Mar 2024 18:03:39 -0300 Subject: [PATCH] ignore code blocks when checking markdown for XSS (#20641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code blocks are rendered as raw strings and therefore don“t need to be checked for XSS. Checking them for XSS disallow users to write articles about XSS in markdown, for example. Co-authored-by: Mac Siri --- app/services/markdown_processor/parser.rb | 5 ++- .../markdown_processor/parser_spec.rb | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/services/markdown_processor/parser.rb b/app/services/markdown_processor/parser.rb index e6e77b73c..b705466e6 100644 --- a/app/services/markdown_processor/parser.rb +++ b/app/services/markdown_processor/parser.rb @@ -5,6 +5,8 @@ module MarkdownProcessor %r{data:text/html[,;][\sa-z0-9]*}i, ].freeze + CODE_BLOCKS_REGEX = /(~{3}|`{3}|`{2}|`)[\s\S]*?\1/ + WORDS_READ_PER_MINUTE = 275.0 # @param content [String] The user input, mix of markdown and liquid. This might be an @@ -95,7 +97,8 @@ module MarkdownProcessor end def catch_xss_attempts(markdown) - return unless markdown.match?(Regexp.union(BAD_XSS_REGEX)) + markdown_without_code_blocks = markdown.gsub(CODE_BLOCKS_REGEX, "") + return unless markdown_without_code_blocks.match?(Regexp.union(BAD_XSS_REGEX)) raise ArgumentError, I18n.t("services.markdown_processor.parser.invalid_markdown_detected") end diff --git a/spec/services/markdown_processor/parser_spec.rb b/spec/services/markdown_processor/parser_spec.rb index b8e2e4849..57d16892a 100644 --- a/spec/services/markdown_processor/parser_spec.rb +++ b/spec/services/markdown_processor/parser_spec.rb @@ -262,6 +262,46 @@ RSpec.describe MarkdownProcessor::Parser, type: :service do generate_and_parse_markdown("```const data = 'data:text/html';```") end.not_to raise_error end + + it "does not raise error if XSS is inside tripe backticks code blocks" do + code_block = "```\n src='data \n```" + + expect { generate_and_parse_markdown(code_block) }.not_to raise_error + end + + it "does not raise error if XSS is inside double backticks code blocks" do + code_block = "`` src='data ``" + + expect { generate_and_parse_markdown(code_block) }.not_to raise_error + end + + it "does not raise error if XSS is inside single backtick code blocks" do + code_block = "` src='data `" + + expect { generate_and_parse_markdown(code_block) }.not_to raise_error + end + + it "does not raise error if XSS is inside triple tildes code blocks" do + code_block = "~~~\n src='data \n~~~" + + expect { generate_and_parse_markdown(code_block) }.not_to raise_error + end + + it "raises and error if XSS attempt is in between codeblocks" do + markdown = <<~MARKDOWN + ``` + code block 1 + ``` + + src='data + + ``` + code block 2 + ``` + MARKDOWN + + expect { generate_and_parse_markdown(markdown) }.to raise_error(ArgumentError) + end end context "when provided with an @username" do