diff --git a/CHANGELOG.md b/CHANGELOG.md index 76cd68a48..51e90cef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Fix cross-site scripting (XSS) vulnerability in handling of linkrefs in plain text messages - Fix so output of log_date_format with microseconds contains time in server time zone, not UTC - Fix so N property always exists in a vCard export (#8771) - Fix so rcmail::format_date() works with DateTimeImmutable input (#8867) diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 3ebbb2f10..b1244329c 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -59,8 +59,8 @@ class rcube_string_replacer $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 @@ -152,7 +152,7 @@ class rcube_string_replacer $matches[0][1] ]; - return $this->get_replacement($this->add('['.$key.']')) . $matches[2][0]; + return $this->get_replacement($this->add('[' . $key . ']')) . $matches[2][0]; } /** diff --git a/tests/Framework/StringReplacer.php b/tests/Framework/StringReplacer.php index 9b3cd6f38..cabb6c660 100644 --- a/tests/Framework/StringReplacer.php +++ b/tests/Framework/StringReplacer.php @@ -63,12 +63,14 @@ class Framework_StringReplacer extends PHPUnit\Framework\TestCase $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); @@ -76,6 +78,6 @@ class Framework_StringReplacer extends PHPUnit\Framework\TestCase $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 without an index entry"); + $this->assertContains('of [Roundcube].[ref<0]', $result, "Don't touch strings without an index entry"); } } diff --git a/tests/Framework/Text2Html.php b/tests/Framework/Text2Html.php index 9d5280060..dcd1c8aea 100644 --- a/tests/Framework/Text2Html.php +++ b/tests/Framework/Text2Html.php @@ -137,6 +137,23 @@ class Framework_Text2Html extends PHPUnit\Framework\TestCase $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 = "
"; + + $this->assertEquals($expected, $html); + } + /** * Test bug #8021 */