Zscaler ZIA - Patient APT: Multi-Channel Low & Slow Exfiltration
35 CSL ZIA Low Slow Multi Channel Exfiltration
Query
let HuntWindow = 30d;
let ExfilDomains = dynamic([
"drive.google.com", "docs.google.com", "dropbox.com", "box.com",
"mega.nz", "mediafire.com", "sendspace.com", "wetransfer.com",
"4shared.com", "anonfiles.com",
"github.com", "gitlab.com", "bitbucket.org", "gist.github.com",
"web.whatsapp.com", "telegram.org", "t.me", "discord.com",
"discordapp.com", "signal.org",
"mail.google.com", "outlook.live.com", "protonmail.com", "tutanota.com"]);
let ZIA_Daily =
CommonSecurityLog
| where TimeGenerated > ago(HuntWindow)
| where DeviceVendor == "Zscaler"
| where DeviceAction !in ("block", "BLOCK", "Blocked", "blocked", "deny")
| where isnotempty(SourceUserName)
| where DestinationHostName has_any (ExfilDomains)
| summarize
DaySentBytes = sum(SentBytes),
DayRequestCount = count(),
DayDestinCount = dcount(DestinationHostName)
by UserName = tolower(SourceUserName), Day = bin(TimeGenerated, 1d);
let ZIA_Users =
ZIA_Daily
| summarize
ZIA_TotalMBSent = round(toreal(sum(DaySentBytes)) / 1048576, 2),
ZIA_ActiveDays = dcount(Day),
ZIA_TotalRequests = sum(DayRequestCount),
ZIA_UniqueDestCnt = sum(DayDestinCount)
by UserName;
let globalAvg = toscalar(ZIA_Users | summarize avg(ZIA_TotalMBSent));
let globalStd = toscalar(ZIA_Users | summarize stdev(ZIA_TotalMBSent));
let O365_Sharing =
OfficeActivity
| where TimeGenerated > ago(HuntWindow)
| where isnotempty(UserId)
| where Operation in (
"FileDownloaded", "FileSyncDownloadedFull", "FileCopied",
"AnonymousLinkCreated", "AnonymousLinkUsed",
"SharingSet", "SharingInvitationCreated",
"AddedToSecureLink", "SecureLinkUsed")
| summarize
O365_EventCount = count(),
O365_Operations = make_set(Operation, 10),
O365_AnonLinks = countif(Operation has "Anonymous"),
O365_LastEvent = max(TimeGenerated)
by UserName = tolower(UserId);
ZIA_Users
| join kind=leftouter O365_Sharing on UserName
| extend
O365_EventCount = coalesce(O365_EventCount, 0),
O365_AnonLinks = coalesce(O365_AnonLinks, 0)
| extend
Zscore = iff(globalStd > 0,
round((ZIA_TotalMBSent - globalAvg) / globalStd, 2),
0.0),
DistinctChannels = iff(ZIA_TotalMBSent > 5, 1, 0)
+ iff(O365_EventCount > 0, 1, 0)
| where Zscore >= 3.0
or (O365_AnonLinks >= 3 and ZIA_TotalMBSent > 10)
or (ZIA_ActiveDays >= 20 and ZIA_TotalMBSent > 50)
| project
UserName,
ZIA_TotalMBSent, ZIA_ActiveDays, ZIA_TotalRequests, ZIA_UniqueDestCnt,
O365_EventCount, O365_AnonLinks, O365_Operations,
DistinctChannels, Zscore
| order by Zscore desc, ZIA_TotalMBSent descExplanation
This query is designed to detect suspicious data exfiltration activities by users over a 30-day period. It focuses on identifying "low and slow" data transfers, where users gradually upload data to non-corporate cloud storage, code-hosting, and messaging platforms, avoiding detection by staying below typical data loss prevention (DLP) thresholds.
Here's a simplified breakdown of what the query does:
-
Data Collection: It collects data from Zscaler logs and Microsoft 365 OfficeActivity logs over the past 30 days.
-
Target Platforms: It looks for uploads to a list of non-corporate platforms like Google Drive, Dropbox, GitHub, WhatsApp, and others.
-
User Activity Analysis:
- Aggregates the total amount of data uploaded by each user.
- Counts the number of days a user was active in uploading data.
- Counts the number of different platforms a user uploaded data to.
-
Anomaly Detection:
- Calculates the average and standard deviation of data uploaded by all users.
- Flags users whose upload volume is significantly higher (≥3 standard deviations) than the average.
- Flags users who create anonymous public links or have upload activity spanning 20 or more days.
-
Output: The query generates a prioritized list of users who exhibit suspicious behavior, potentially indicating advanced persistent threats (APT) or insider threats. These users are flagged for further manual investigation.
-
Alerting: If any suspicious activity is detected, an alert is created with details about the user's activity, including the amount of data uploaded, the number of active days, and any anonymous links created.
The query is scheduled to run daily and is configured to create incidents for further investigation if any suspicious activity is detected.
Details

David Alonso
Released: March 2, 2026
Tables
Keywords
Operators
Severity
HighTactics
Frequency: P1D
Period: P30D