From One Account to Every Mailbox: Breaking Zimbra's Identity Boundaries (Part 1)

Source: Rapid7•

From One Account to Every Mailbox: Breaking Zimbra's Identity Boundaries (Part 1)

An enterprise mail server authenticates users, stores private communications, delivers recovery links, runs calendars, and sends mail that employees and other systems trust. Compromising it can therefore expose both email and the identities and workflows built around it. During a broader…

An enterprise mail server authenticates users, stores private communications, delivers recovery links, runs calendars, and sends mail that employees and other systems trust. Compromising it can therefore expose both email and the identities and workflows built around it.

During a broader assessment of Zimbra Collaboration Suite (ZCS), Rapid7 reported more than 80 vulnerabilities spanning authentication, mailbox authorization, calendar processing, web clients, document services, and the host operating system. The affected components are being fixed on different schedules, so we are publishing the analysis in stages. An accompanying GitHub repository containing full write-ups and PoCs serves as a live technical tracker, and will be updated as further findings and fixes become public.

This first article concentrates on five account-related vulnerabilities:

CVE

Finding

Rapid7 CVSS

Fixed release

GraphQL authentication rate-limit bypass

No public fix listed

LDAP filter injection

No public fix listed

Email impersonation via SaveDraftRequest

ZCS 10.1.17

EWS cross-user mailbox access

ZCS 10.1.20

Sieve notify forwarding-restriction bypass

ZCS 10.1.20

Part 2 will cover unauthenticated stored XSS paths in the Classic and Modern clients and what they can do with the recipient's session. A script can install the Sieve forwarding rule (CVE-2026-50055); another path preserves direct mailbox access after the original session expires or the victim changes their password. CVE-2026-73571 makes these attacks more credible by placing the message in the mailbox as any chosen local user.

Parts 3 and 4 move through the document-service boundary from SSRF to code execution as zimbra, then cover multiple independent paths from zimbra to root. The BruCON presentation, Signed, Sealed, Compromised: Weaponizing Enterprise Mail Infrastructure, previewed these chains, including selected root-command output returned to the victim's browser after one message selection.

Product description

Zimbra Collaboration Suite is a self-hosted platform for email, calendars, contacts, tasks, and file sharing. Zimbra calls its commercial server Network Edition. Within one Network Edition installation, customers can license a mixture of Standard and Professional users. Zimbra Desktop and Zimbra Connector for Outlook are separate client applications, while Exchange Web Services (EWS) is a separately licensed server feature for Outlook compatibility.

ZCS includes two webmail clients with different request and rendering stacks: Classic relies primarily on SOAP, while Modern uses GraphQL. The server also accepts SMTP and iCalendar input, exposes compatibility services such as EWS, and delegates work to local components running under several operating-system identities.

Testing setup

Rapid7 initially assessed ZCS 10.1.16_GA_4850 Network Edition on Ubuntu 22.04. For fixed findings, each section describes Zimbra's fix and the accompanying Github repository retains the complete vulnerable-to-fixed diff.

Impact

The pre-authentication findings lower separate barriers to obtaining a foothold. GraphQL hides failed password attempts from Zimbra's source-IP counter. In the configured external-LDAP case, a second flaw can also leave the optional account-lockout policy with no local account to lock.

Each remaining finding is independently exploitable from an ordinary compromised account. Email impersonation needs no optional feature: the attacker places a different local address in an authenticated request. Zimbra submits the message from that account through the trusted outbound pipeline and records a copy in the selected user's Sent folder.

If EWS is enabled for the compromised account, the attacker can read private conversations, attachments, drafts, sent mail, contacts and calendar entries from other users' mailboxes. A separate Sieve policy bypass can keep copies of future mail flowing to the attacker after the original session expires or the password changes.

These examples do not represent everything an attacker can do with authenticated Zimbra access, or the full vulnerability set from the assessment.

GraphQL authentication rate-limit bypass (CVE-2026-93637)

This pre-authentication route requires only HTTPS access to Zimbra. ZimbraInvalidLoginFilter normally records failed logins by source address around requests to the public service endpoints. Classic submits login attempts through the SOAP AuthRequest path, whereas Modern exposes the same password check through its GraphQL authenticate mutation.

That limiter's failure threshold is 10 by default, and after a source crosses it within the configured window, subsequent requests handled by the filter receive HTTP 503. CVE-2026-93637 allows attempts through GraphQL to remain invisible to that counter.

Technical analysis

The failure counter relies on a request attribute

ZimbraInvalidLoginFilter wraps requests to the public service endpoints and runs the downstream handler before its counter logic:

At [0], failure processing begins only if the downstream path added auth.failed to the request. The relevant SOAP exception path is:

At [1], SoapEngine.dispatchRequest() sets the attribute before returning the authentication fault. A failed SOAP login therefore reaches the check at [0] and increments the source-IP counter.

GraphQL skips the SOAP failure handler

Modern Zimbra's GraphQL extension builds an ordinary AuthRequest, then reaches its handler through XMLDocumentUtilities.executeDocumentAsGuest():

At [2], the helper calls the authentication handler without passing through SoapEngine. An incorrect password still becomes a GraphQL error, but the catch block at [1] never runs. The attribute read at [0] is absent, so the filter does not increment the source-IP counter.

Exploitation

Batched authentication

An unauthenticated client sends JSON to /service/extension/graphql. GraphQL aliases let its query field invoke authenticate repeatedly with different passwords:

Each alias performs a real authentication operation. Failures appear in the GraphQL errors array, while a successful alias returns an authentication token under its corresponding name. The GraphQL engine imposes no application-level alias limit on this path. The whole document remains one HTTP request, so Jetty's request-count control sees one request rather than the number of login operations inside it.

Alias execution is sequential and backend-bound, so the rate depends on the deployment. Using 100 aliases per request, 10,000 candidates completed in under two minutes without the Zimbra IP counter or Jetty's request filter blocking the source. The vulnerability removes IP-level failed-login accounting and reduces request overhead.

The CVE-2026-93637 PoC accepts an ordinary password file, generates the batched GraphQL documents and reports the accepted candidate.

Figure 1: Metasploit module tests 1500 passwords in 15 requests, successfully identifying the correct password in the final batch.

Per-account lockout

The IP counter is not Zimbra's only possible control. Its separate per-account lockout policy is disabled by default, but when enabled, failed GraphQL operations still increment the target local account's counter and stop further guessing when that account locks.

CVE-2026-93635 and external LDAP

On domains configured with external LDAP search-filter authentication and lazy auto-provisioning, CVE-2026-93635 turns the login field into a password oracle for an external directory user. LdapUtil.computeDn() substitutes a wildcarded login such as jdoe*@example.test into the configured filter without escaping it. If that pattern selects one directory entry, Zimbra tries the candidate password against that user. An incorrect password returns account.AUTH_FAILED; a correct password passes the LDAP bind and reaches lazy provisioning, producing a different response.

The wildcarded login is not the name of an existing local Zimbra account, so the optional per-account lockout has no account against which to record the failed attempt. Sending the same operation through GraphQL also avoids the source-IP counter. With per-account lockout enabled and its threshold set to five, repeated wrong candidates incremented neither counter, while a correct password remained distinguishable. This two-bug composition applies only to the stated external-LDAP configuration, not Zimbra's default local-authentication path.

The LDAP/GraphQL composition PoC and CVE-2026-93635 tracker entry cover this configured external-directory path in detail. The CVE-2026-93637 tracker entry records the standalone finding and affected-version evidence.

Impact

Anyone who can reach the public GraphQL endpoint can make repeated password guesses without triggering Zimbra's source-IP suspension. Batching several candidates also reduces the number of HTTP requests and the associated network overhead. This makes weak, reused or previously exposed passwords more practical to test, but it does not reveal a strong password or bypass a separate MFA check.

Email impersonation via SaveDraftRequest (CVE-2026-73571)

SaveDraftRequest has a delegated-sending path selected by isDelegatedReq. On a vulnerable server, an ordinary user can place another local address in the request's From field. The handler resolves that address to its mailbox, assumes the mailbox owner's authority and calls Zimbra's normal send routine without checking whether the signed-in account has send-as rights. This is an application authorization failure, not a forged display name or a hand-written SMTP header: Zimbra submits the attacker's message as the selected account and adds the corresponding item to that account's Sent folder.

The target must be on the same mailbox server, but the attack requires no optional Zimbra feature, existing delegation, administrator right or victim action.

Technical Analysis

Claimed sender becomes mailbox authority

After the request parser extracts the From address, the delegated branch resolves that address to a local account and reads an optional delegateeAccountId:

There is no checkRight(), canAccessAccount(), or canSendAs() call between resolving the account at [0] and delivery at [3]. In the demonstrated request, delegateeAccountId is absent. At [2], Zimbra constructs the operation context from the mailbox named in From, causing the later send to treat the selected account as the caller. [3] then submits the message through Zimbra's legitimate sending path.

There is a second way to trigger the flaw. The attacker can supply the claimed sender's account UUID in delegateeAccountId. At [1], Zimbra constructs the operation context directly from that account and reaches the same impersonation result without checking the identity that was actually signed in.

Exploitation

Sending as a local identity

The relevant SaveDraftRequest body is:

Because Zimbra submits the message through its legitimate infrastructure, the issue goes beyond display-name spoofing. On a deployment whose legitimate outbound mail passes SPF, DKIM, and DMARC, the impersonated message passes them too: it uses the same source MTA, signing domain, RFC sender, and envelope sender as legitimate mail from the selected account. Local testing confirmed that sender alignment and normal MTA path.

The CVE-2026-73571 PoC submits the delegated request with an operator-selected sender, recipient, subject and message body. On the affected build, the message arrived with the CEO as its RFC sender, and the same subject appeared in the CEO's Sent folder.

Figure 2: The victim's Inbox displays the forged message as an ordinary internal email from the CEO.

Impact

An attacker can impersonate any local user, not only an administrator or executive. Internally, that allows believable payment requests, changes to account details, malicious links, false instructions and fraudulent approvals. Normal display-name spoofing warnings and external-sender banners do not help because Zimbra submits the message as the selected local user.

Zimbra also places the forged message in the impersonated user's Sent folder. This leaves a fabricated record of authorship and can support an attempt to frame that user.

Figure 3: The same forged message is recorded in the CEO's Sent folder.

For external recipients, the attacker can send from a finance account to request new payment details, use an operations account to cancel or alter an order, or send scams and abusive mail under an employee's address. The consequences depend on the role and relationships of the selected sender.

The same trusted-delivery advantage applies to exploit-bearing mail. The next article will examine browser-side findings that an attacker can deliver from any chosen local account. Impersonation is not required for the XSS itself, but can make the message appear to come from somebody the recipient trusts.

Fix

The patch in ZCS 10.1.17 retains the account that actually signed in unless it has an explicit send-as or send-on-behalf-of right. An unauthorized delegated request consequently runs as the caller rather than the account named in the message.

EWS cross-user mailbox access (CVE-2026-10631)

Zimbra's EWS extension uses composite folder IDs intended for shared-mailbox operations. FindItem trusts the owner UUID inside an attacker-supplied ID and constructs the authorization context from the selected mailbox instead of the account that signed in. This Insecure Direct Object Reference (IDOR) lets any ordinary EWS-enabled account read complete items from other users' mailboxes without a share or delegation grant.

The attacker needs zimbraFeatureEwsEnabled=TRUE. Although disabled by default, deployments using Zimbra's Outlook desktop integration commonly enable EWS class-of-service-wide. The target account does not need EWS enabled, and no target-user action is required.

Technical analysis

Composite IDs select the mailbox

To address a shared item, EWS needs to identify both the mailbox that owns it and the item or folder inside that mailbox. Zimbra encodes this as {ownerUUID}_{numericId}. For example:

When FindItem receives a composite ID, FolderUtil.parseItemId() separates the owner and numeric portions. The owner value is then passed to ItemUtil.getGrantorMailbox():

At [0], EWS resolves the supplied owner UUID to a local account; [1] retrieves that account's mailbox. Neither method receives the caller's identity.

The mailbox becomes the authenticated identity

The authenticated account and selected mailbox are then passed to ItemOperation:

[2] is the attacker account. Supplying a victim UUID makes [3] the victim mailbox, so it is not null. [4] therefore creates OperationContext from the victim mailbox instead of the attacker account.

[5] extracts the victim account from that mailbox, and [6] stores the victim as the authenticated user. The mailbox then compares this identity with its owner:

The identities match, so [7] changes the authenticated user to null, which downstream checks treat as owner access. The attacker's request is consequently authorized as the victim. EWS has used the untrusted owner UUID both to select a mailbox and to decide who is authenticated. The numeric folder ID is subsequently resolved within that owner context, allowing FindItem to access any folder in the selected mailbox.

Exploitation

Resolving a target mailbox

A target UUID is available through ordinary authenticated directory lookups. Both GetAccountInfoRequest and SearchGalRequest return zimbraId for a known local address. The PoC uses GetAccountInfoRequest:

The response contains the target's UUID:

Appending _2 to the UUID forms the target's Inbox identifier. The attacker sends the following EWS request to /service/extension/zimbraews, or to /EWS/Exchange.asmx when EWS is exposed through Zimbra's standard proxy:

The server returns the selected mailbox's data in the EWS response:

The CVE-2026-10631 PoC obtains that UUID and creates the composite ID automatically.

Cross-account folder reads

Changing the numeric component selects another well-known folder:

Folder

Crafted ID

Unauthorized result

Inbox

{uuid}_2

Received messages and attachments

Sent

{uuid}_5

Messages sent by the target

Drafts

{uuid}_6

Unfinished messages

Contacts

{uuid}_7

Address-book entries

Calendar

{uuid}_10

Appointments and meeting data

If the target mailbox is on another server in the same Zimbra cluster, the first server forwards the crafted request. The receiving server resolves its local mailbox from the same owner UUID and reaches the vulnerable FindItem constructor.

The CVE-2026-10631 tracker entry covers the full response, affected folders and multi-server path in detail.

Impact

EWS exposes the victim's private message bodies and attachments, as well as drafts, sent mail, contacts and calendar data. The attacker can monitor conversations and use their history to make the separate impersonation attack more credible.

An attacker can also request a password reset for another service, monitor the corresponding mailbox and consume the link. EWS does not bypass third-party MFA by itself, but it exposes an email channel that many services still treat as sufficient proof. Because the owner UUID is attacker-selected, the same ordinary EWS account can repeat these reads against other local mailboxes.

Note that an earlier version of this analysis, presented at BruCON 2026, attributed GetItem, send, move and delete to the same flaw. Comparing intermediate Network Edition releases during this research required multiple restored VM appliances, because EWS is license-gated and normal patching advances the complete system; one appliance retained a separate mailbox authorization state that obscured the boundary, which initially made the impact appear broader. Repeating each operation with explicit authorization and target-state controls narrowed the CVE to FindItem, which still exposes complete MIME and attachments.

Fix

The in ZCS 10.1.20 creates the EWS authorization context from the account that signed in, not the mailbox selected by the composite ID. Zimbra applied that correction to both local and remote mailbox operations.

Sieve notify forwarding-restriction bypass (CVE-2026-50055)

zimbraFeatureMailForwardingInFiltersEnabled=FALSE is meant to stop users creating server-side mail-forwarding rules. Zimbra enforces it by rejecting Sieve redirect, but accepts notify even though that action can send selected headers and the complete text body to an arbitrary external address. An authenticated user can therefore install persistent mail exfiltration despite the administrator's restriction. If forwarding is normally allowed, there is no policy boundary to bypass.

Technical analysis

Redirect is the only blocked action

Both the ModifyFilterRulesRequest and ModifyOutgoingFilterRulesRequest SOAP commands call checkForwardFilterAttr() before saving a rule. The check recognizes only one action type:

At [0], the policy classifies only RedirectAction as forwarding, meaning NotifyAction and RFCCompliantNotifyAction reach [1] even though they can send attacker-selected message content to an external email address.

Notify expands message content

These actions can include message content rather than just a generic alert because SoapToSieve.getSieveScript() enables the variables and enotify extensions. FilterUtil.getVarsMap() then supplies the values available to the notification:

When the rule runs, Notify.executeBasic() expands those variables into the notification subject and body. [2] makes decoded headers available, and [3] supplies the text part selected by Mime.getTextBody(). It does not supply raw MIME or attachments.

Exploitation

Installing persistent exfiltration

An authenticated user can place the following rule object inside ModifyFilterRulesRequest:

actionKeep leaves the original message in the user's Inbox, while each matching delivery sends the selected message text and headers to the external address.

The CVE-2026-50055 PoC preserves existing filters while installing the notify rule. After an ordinary message arrived for the filtered account, another mailbox received its subject, sender, recipients, date and complete text body. The CVE-2026-50055 tracker entry has the complete affected-version information.

Figure 4: The notification delivered to the attacker contains the subject, headers and complete text body of the victim's message.

Hidden from Modern

The persistence is not apparent in Modern. During testing, the server returned the active notification rule while the same account's Filters view remained empty. The server continued to run the rule normally, but Modern did not give the account owner a way to discover or remove it.

Figure 5: Modern's Filters view does not display the active Sieve notify rule.

Classic did list the attacker-selected name under Active Filters, but its overview did not expose the notification address or copied fields. The rule is therefore not invisible from every client, and an attacker can choose a less conspicuous name.

Figure 6: Classic displays the attacker's rule name but not the external destination or copied fields.

Impact

The flaw defeats an administrator's attempt to prevent users from forwarding mail with server-side filters. An attacker with an authenticated session can install the rule directly. It continues to disclose future message text and headers after that session expires or the password changes, without appearing in Modern's Filters view. It does not forward attachments or raw MIME.

Fix

The in ZCS 10.1.20 treats notify and its RFC-compliant variant as forwarding actions and rejects them under the same account policy as redirect.

Apply the latest supported Zimbra release. Zimbra's security advisory lists CVE-2026-73571 as fixed in ZCS 10.1.17 and CVE-2026-10631 and CVE-2026-50055 as fixed in ZCS 10.1.20. No fixed release is publicly listed for CVE-2026-93635 or CVE-2026-93637 at the time of publication, so install the security update containing those fixes when Zimbra releases it.

Upgrading does not remove filter rules already saved to accounts. Administrators should inspect the stored incoming and outgoing filter rules for external actionNotify and RFC-compliant notify actions that violate forwarding policy; Modern's Filters view is not sufficient for this review.

Detection and Incident Response

A reverse proxy or web application firewall that inspects request bodies can detect multiple authenticate aliases in one anonymous GraphQL request. Zimbra's EWS logs expose cross-user operations involving two different account UUIDs, as shown in the EWS IoCs. Saved notify rules and outbound notification traffic provide more direct evidence of the Sieve path.

EWS creates no delegation grant to revoke, Sieve rules remain as saved account state, and sender impersonation can generate ordinary Sent and MTA artifacts. Recovery must cover those server-side changes and any other mailbox reached, not only the password of the account first compromised.

Credit

The assessment was conducted by Jonah Burgess (CryptoCat), Senior Security Researcher at Rapid7, in accordance with Rapid7's vulnerability disclosure policy.

Disclosure timeline

  • April 17, 2026: Rapid7 submitted an initial report covering 23 findings.

April 17, 2026: Rapid7 submitted an initial report covering 23 findings.

  • April 24, 2026: Zimbra acknowledged the report.

April 24, 2026: Zimbra acknowledged the report.

  • May 21, 2026: Zimbra confirmed they validated 10 of the 23 findings, three of which were duplicates.

May 21, 2026: Zimbra confirmed they validated 10 of the 23 findings, three of which were duplicates.

  • May 28, 2026: ZCS 10.1.17 fixed CVE-2026-73571.

May 28, 2026: ZCS 10.1.17 fixed CVE-2026-73571.

  • June 1, 2026: Zimbra requested an embargo on publication until the planned ZCS 10.1.18 release in September.

June 1, 2026: Zimbra requested an embargo on publication until the planned ZCS 10.1.18 release in September.

  • June 16 and July 7, 2026: ZCS 10.1.18 and 10.1.19 were released without additional fixes from the initial report.

June 16 and July 7, 2026: ZCS 10.1.18 and 10.1.19 were released without additional fixes from the initial report.

  • July 15, 2026: Zimbra and Rapid7 agreed on September 24 as the coordinated disclosure date.

What this article says