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.0
+0200
+++ roundcube-1.2.3+dfsg.1/debian/changelog 2020-08-11 18:38:40.0
+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 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.0 +0100
+++ roundcube-1.2.3+dfsg.1/debian/patches/CVE-2020-16145.patch 2020-08-11
18:38:40.0 +0200
@@ -0,0 +1,107 @@
+commit 589d36010048300ed39f4887aab1afd3ae98d00e
+Author: Aleksander Machniak
+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 fa