Roundcube Webmail: SVG feImage bypasses image blocking to track email opens

Published: (February 8, 2026 at 01:24 PM EST)
3 min read

Source: Hacker News

TL;DR

Roundcube’s rcube_washtml sanitizer blocked external resources on , , and , but not on . 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

FieldValue
VendorRoundcube
ProductRoundcube Webmail
Affected versions, `href` on and “) and runs them through is_image_attribute(). That function blocks external URLs.

Discovery

I got bored during my Christmas vacation and a SVG‑based XSS fix via the animate tag appeared on my radar. One SVG bug usually means more.1 I spent a few hours reviewing rcube_washtml.php, checking which SVG elements were on the allowlist and how their attributes are sanitized.

stood out.[^2] Its `href` gets fetched on render, same as. But the sanitizer sends it through wash_link() instead of is_image_attribute(). Consequently, the “Block remote images” setting doesn’t apply to it.

Technical details

In wash_attribs(), every attribute hits a chain of checks. The first matching check wins:

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
}

is_image_attribute() (pre‑fix)

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.

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

Thus, for “:

  • is_image_attribute('feimage', 'href')false
  • is_link_attribute('feimage', 'href')true

The URL is processed by wash_link(), which passes HTTP/HTTPS URLs straight through.

Proof of concept

An invisible 1×1 SVG, positioned off‑screen:

<svg width="0" height="0" style="position:absolute; left:-9999px;">
  <filter id="track">
    <feImage href="https://attacker.example.com/track.png" />
  </filter>
  <rect width="1" height="1" filter="url(#track)" />
</svg>

When rendered, the browser evaluates the SVG filter and issues a GET request to the attacker‑controlled URL, revealing that the email was opened.

Impact

The “Block remote images” setting does not block this remote image. An attacker can confirm that the recipient opened the email, log their IP address, and fingerprint the browser.

Remediation

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

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

Now “ matches is_image_attribute(), is routed through wash_uri(), and the remote URL is blocked.

Action: Update to Roundcube 1.5.13 or 1.6.13 (or later).

Timeline

DateEvent
2026‑01‑04Reported to Roundcube
2026‑02‑081.5.13 and 1.6.13 released
2026‑02‑08This post published

Footnotes

Footnotes

  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 haven’t been checked.

0 views
Back to Blog

Related posts

Read more »

Claude Code Is Being Dumbed Down

!Am I out of touch? No, it's the users who are wrong.https://symmetrybreak.ing/images/dont-worry-about-claude/am-i-out-of-touch.webp !Am I out of touch? No, it'...

NetNewsWire Turns 23

Release History NetNewsWire 1.0 for Mac shipped 23 years ago today! 🎸🎩🕶️ Current Work We just shipped 7.0 for Mac and iOS, and now we’re working on NetNewsW...