Dear security team, In a recent post roundcube webmail upstream has announced the following security fix for #968216:
Cross-site scripting (XSS) via HTML messages with malicious SVG or math content (CVE-2020-16145) AFAICT CVE-2020-16145 is only about SVG not math, but the upstream commit addresses both so I opened a single bug: https://github.com/roundcube/roundcubemail/commit/589d36010048300ed39f4887aab1afd3ae98d00e Debdiff tested and attached, but I'd appreciate if you could take care of the DLA :-) Thanks! Cheers, -- Guilhem.
diffstat for roundcube-1.2.3+dfsg.1 roundcube-1.2.3+dfsg.1 changelog | 8 +++ patches/CVE-2020-16145.patch | 107 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 116 insertions(+) diff -Nru roundcube-1.2.3+dfsg.1/debian/changelog roundcube-1.2.3+dfsg.1/debian/changelog --- roundcube-1.2.3+dfsg.1/debian/changelog 2020-07-06 16:14:59.000000000 +0200 +++ roundcube-1.2.3+dfsg.1/debian/changelog 2020-08-11 18:38:40.000000000 +0200 @@ -1,3 +1,11 @@ +roundcube (1.2.3+dfsg.1-4+deb9u7) stretch-security; urgency=high + + * Backport security fix for CVE-2020-16145: Cross-site scripting (XSS) + vulnerability via HTML messages with malicious svg or math + content. (Closes: #968216) + + -- Guilhem Moulin <guil...@debian.org> Tue, 11 Aug 2020 18:38:40 +0200 + roundcube (1.2.3+dfsg.1-4+deb9u6) stretch; urgency=high * Backport security fix for CVE-2020-15562: Cross-Site Scripting (XSS) diff -Nru roundcube-1.2.3+dfsg.1/debian/patches/CVE-2020-16145.patch roundcube-1.2.3+dfsg.1/debian/patches/CVE-2020-16145.patch --- roundcube-1.2.3+dfsg.1/debian/patches/CVE-2020-16145.patch 1970-01-01 01:00:00.000000000 +0100 +++ roundcube-1.2.3+dfsg.1/debian/patches/CVE-2020-16145.patch 2020-08-11 18:38:40.000000000 +0200 @@ -0,0 +1,107 @@ +commit 589d36010048300ed39f4887aab1afd3ae98d00e +Author: Aleksander Machniak <a...@alec.pl> +Date: Sun Aug 9 18:02:16 2020 +0200 + + Fix cross-site scripting (XSS) via HTML messages with malicious svg or math content + +diff --git a/program/lib/Roundcube/rcube_washtml.php b/program/lib/Roundcube/rcube_washtml.php +index 4c5ca46a3..81a3edf1b 100644 +--- a/program/lib/Roundcube/rcube_washtml.php ++++ b/program/lib/Roundcube/rcube_washtml.php +@@ -365,7 +365,30 @@ class rcube_washtml + return $this->config['blocked_src']; + } + } +- else if (preg_match('/^data:image.+/i', $uri)) { // RFC2397 ++ else if (preg_match('/^data:image\/([^,]+),(.+)$/i', $uri, $matches)) { // RFC2397 ++ // svg images can be insecure, we'll sanitize them ++ if (stripos($matches[1], 'svg') !== false) { ++ $svg = $matches[2]; ++ ++ if (stripos($matches[1], ';base64') !== false) { ++ $svg = base64_decode($svg); ++ $type = $matches[1]; ++ } ++ else { ++ $type = $matches[1] . ';base64'; ++ } ++ ++ $washer = new self($this->config); ++ $svg = $washer->wash($svg); ++ ++ // Invalid svg content ++ if (empty($svg)) { ++ return null; ++ } ++ ++ return 'data:image/' . $type . ',' . base64_encode($svg); ++ } ++ + return $uri; + } + } +@@ -375,7 +398,7 @@ class rcube_washtml + */ + private function is_link_attribute($tag, $attr) + { +- return ($tag == 'a' || $tag == 'area') && $attr == 'href'; ++ return $attr === 'href'; + } + + /** +@@ -387,6 +410,7 @@ class rcube_washtml + || $attr == 'color-profile' // SVG + || ($attr == 'poster' && $tag == 'video') + || ($attr == 'src' && preg_match('/^(img|source)$/i', $tag)) ++ || ($tag == 'use' && $attr == 'href') // SVG + || ($tag == 'image' && $attr == 'href'); // SVG + } + +@@ -399,6 +423,31 @@ class rcube_washtml + 'marker-end', 'marker-mid', 'clip-path', 'mask', 'cursor')); + } + ++ /** ++ * Check if a specified element has an attribute with specified value. ++ * Do it in case-insensitive manner. ++ * ++ * @param DOMElement $node The element ++ * @param string $attr_name The attribute name ++ * @param string $attr_value The attribute value to find ++ * ++ * @return bool True if the specified attribute exists and has the expected value ++ */ ++ private static function attribute_value($node, $attr_name, $attr_value) ++ { ++ $attr_name = strtolower($attr_name); ++ ++ foreach ($node->attributes as $name => $attr) { ++ if (strtolower($name) === $attr_name) { ++ if (strtolower($attr_value) === strtolower($attr->nodeValue)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; ++ } ++ + /** + * The main loop that recurse on a node tree. + * It output only allowed tags with allowed attributes and allowed inline styles +@@ -433,6 +482,15 @@ class rcube_washtml + switch ($node->nodeType) { + case XML_ELEMENT_NODE: //Check element + $tagName = strtolower($node->tagName); ++ ++ if (in_array($tagName, array('animate', 'animatecolor', 'set', 'animatetransform')) ++ && self::attribute_value($node, 'attributename', 'href') ++ ) { ++ // Insecure svg tags ++ $dump .= "<!-- $tagName blocked -->"; ++ break; ++ } ++ + if ($callback = $this->handlers[$tagName]) { + $dump .= call_user_func($callback, $tagName, + $this->wash_attribs($node), $this->dumpHtml($node, $level), $this); diff -Nru roundcube-1.2.3+dfsg.1/debian/patches/series roundcube-1.2.3+dfsg.1/debian/patches/series --- roundcube-1.2.3+dfsg.1/debian/patches/series 2020-07-06 16:14:59.000000000 +0200 +++ roundcube-1.2.3+dfsg.1/debian/patches/series 2020-08-11 18:38:40.000000000 +0200 @@ -21,3 +21,4 @@ CVE-2020-13964.patch CVE-2020-13965.patch CVE-2020-15562.patch +CVE-2020-16145.patch
signature.asc
Description: PGP signature