From c998034d312ef04f1801c7df6ba649d51d749436 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 14 Sep 2023 08:39:51 +0200 Subject: [PATCH] Fix cross-site scripting (XSS) vulnerability in handling of linkrefs in plain text messages Thanks to Niraj Shivtarkar for the report. --- CHANGELOG | 4 ++-- program/lib/Roundcube/rcube_string_replacer.php | 4 ++-- tests/Framework/StringReplacer.php | 12 +++++++----- tests/Framework/Text2Html.php | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ba1af734633..1eecbfec89b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ -CHANGELOG Roundcube Webmail -=========================== +# Changelog Roundcube Webmail +- Fix cross-site scripting (XSS) vulnerability in handling of linkrefs in plain text messages - Enigma: Fix initial synchronization of private keys RELEASE 1.4.13 diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 8c55cb29a02..5f5a41fca66 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -59,8 +59,8 @@ function __construct($options = array()) $link_prefix = "([\w]+:\/\/|{$this->noword}[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)"; $this->options = $options; - $this->linkref_index = '/\[([^\]#]+)\](:?\s*' . substr($this->pattern, 1, -1) . ')/'; - $this->linkref_pattern = '/\[([^\]#]+)\]/'; + $this->linkref_index = '/\[([^<>\]#]+)\](:?\s*' . substr($this->pattern, 1, -1) . ')/'; + $this->linkref_pattern = '/\[([^<>\]#]+)\]/'; $this->link_pattern = "/$link_prefix($utf_domain([$url1]*[$url2]+)*)/"; $this->mailto_pattern = "/(" . "[-\w!\#\$%&*+~\/^`|{}=]+(?:\.[-\w!\#\$%&*+~\/^`|{}=]+)*" // local-part diff --git a/tests/Framework/StringReplacer.php b/tests/Framework/StringReplacer.php index ace8bf677dd..16dff6a5ab3 100644 --- a/tests/Framework/StringReplacer.php +++ b/tests/Framework/StringReplacer.php @@ -64,12 +64,14 @@ function test_replace($input, $output) $this->assertEquals($output, $result); } + /** + * Test link references + */ function test_linkrefs() { - $input = "This is a sample message [1] to test the new linkref [ref0] replacement feature of [Roundcube].\n"; - $input.= "\n"; - $input.= "[1] http://en.wikipedia.org/wiki/Email\n"; - $input.= "[ref0] www.link-ref.com\n"; + $input = "This is a sample message [1] to test the linkref [ref0] replacement feature of [Roundcube].[ref<0]\n" + . "[1] http://en.wikipedia.org/wiki/Email\n" + . "[ref0] www.link-ref.com\n"; $replacer = new rcube_string_replacer; $result = $replacer->replace($input); @@ -77,6 +79,6 @@ function test_linkrefs() $this->assertContains('[1] to', $result, "Numeric linkref replacements"); $this->assertContains('[ref0] repl', $result, "Alphanum linkref replacements"); - $this->assertContains('of [Roundcube].', $result, "Don't touch strings wihtout an index entry"); + $this->assertContains('of [Roundcube].[ref<0]', $result, "Don't touch strings wihtout an index entry"); } } diff --git a/tests/Framework/Text2Html.php b/tests/Framework/Text2Html.php index db2dbac3156..1d6ffd2aff3 100644 --- a/tests/Framework/Text2Html.php +++ b/tests/Framework/Text2Html.php @@ -137,4 +137,21 @@ function test_text2html_xss() $this->assertEquals($expected, $html); } + + /** + * Test XSS issue + */ + function test_text2html_xss2() + { + $input = "\n[] https://google.com\n"; + $t2h = new rcube_text2html($input); + + $html = $t2h->get_html(); + + $expected = "

\n[<script>evil</script>] " + . "https://google.com
\n" + . "
"; + + $this->assertEquals($expected, $html); + } }