Data Exfiltration Detection: Watch Egress Volume by Actor
Last verified on Nov 8, 2026.
Data leaves a system in many legitimate ways: customer exports, report downloads, backups and API responses. It also leaves in the way you are trying to catch, as a bulk read by a compromised account or an insider with a laptop. MITRE ATT&CK defines exfiltration as the adversary trying to steal data, and notes that adversaries often package data by compressing and encrypting it before removing it. By the time a human notices, the transfer is over.
The signal is size, not content. You rarely know what an attacker took, but you can know that one actor pulled a CSV 50 times larger than anything they or anyone else has downloaded before.
What the evidence looks like
At the application layer, evidence is a large response or export tied to an actor.
{
"ts": "2026-11-07T22:48:15Z",
"event": "export.completed",
"actor": "u_9912",
"tenant": "t_310",
"format": "csv",
"rows": 2310442,
"bytes": 486311920,
"duration_ms": 93310
}This is an example. If that actor's previous exports were 300 to 5,000 rows, the row count is the anomaly. At the infrastructure layer, evidence is flow records and object-store logs. The AWS VPC flow log record includes a bytes field with the number of bytes transferred in the flow, alongside source and destination addresses. Amazon S3 server access logs include a Bytes Sent field, the number of response bytes sent. CloudTrail data events, when enabled, record object-level API activity.
Other shapes: many small responses adding up over hours, a new destination address receiving gigabytes from a database host, or egress at an hour when the account is normally idle.
How to detect it step by step
1. Put a size on every response and export. Log response bytes, row counts and the actor on endpoints that return data. Exports and reports deserve their own events, as above.
2. Measure per actor against their own history. A ratio to the actor's own median or 99th percentile is more useful than a global limit.
WITH today AS (
SELECT actor, sum(bytes) AS bytes_today
FROM egress_events WHERE ts > now() - INTERVAL '1 day' GROUP BY actor),
hist AS (
SELECT actor, percentile_cont(0.5) WITHIN GROUP (ORDER BY daily_bytes) AS median_bytes
FROM (SELECT actor, date_trunc('day', ts) AS d, sum(bytes) AS daily_bytes
FROM egress_events WHERE ts BETWEEN now() - INTERVAL '31 days' AND now() - INTERVAL '1 day'
GROUP BY 1, 2) x GROUP BY actor)
SELECT t.actor, t.bytes_today, h.median_bytes, t.bytes_today / NULLIF(h.median_bytes, 0) AS ratio
FROM today t LEFT JOIN hist h USING (actor)
WHERE t.bytes_today > 100000000 AND (h.median_bytes IS NULL OR t.bytes_today > 20 * h.median_bytes)3. Watch network egress by destination. From flow logs, sum bytes by source host and destination address for traffic leaving your network, and compare each pair with the previous 30 days. A database or internal service sending data to an address it has never talked to is worth a look.
4. Watch object-store reads. Sum Bytes Sent by requester and bucket from access logs. A principal that downloads an entire bucket, or a key prefix it never touched, shows up quickly.
5. Combine size with context. A large export from a new location, right after a privilege change or after a run of failed logins, deserves a higher severity than a large export during the monthly reporting window.
Thresholds and pitfalls
Use two limits together: an absolute floor so small actors with tiny medians do not alert on trivial amounts, and a ratio such as 20 times the actor's median so large legitimate users do not alert constantly. Tune the numbers on a month of your own data before paging anyone.
Common false positives:
- Scheduled exports. Month-end reports and finance pulls recur. Add the calendar to the baseline or tag scheduled jobs separately.
- Backups and replication. Large, regular and expected. Allowlist the identity and destination.
- Compression. Response bytes after compression understate content size. Log row counts as well as bytes.
- CDN and cache. Egress at the origin may differ from egress at the edge. Measure where the data leaves your control.
- New customers. An actor with no history has no baseline. Fall back to the tenant or plan average.
Window size matters. A thief who reads in small pieces will not trip a per-request limit, so alert on cumulative bytes per actor per hour and per day.
What to do when it fires
Identify the actor, the dataset and the destination. Then decide quickly whether it was expected by asking the owner of the account. If not, revoke the session or key, and block the destination. Record what was read: your own access logs for that actor give the list of records and tenants affected, which drives breach notification obligations.
Afterward, add a limit at the source: pagination caps on API responses and a ceiling or approval step on exports. Related guides: access anomalies covers enumeration, privilege changes often precedes a bulk read and authentication anomalies covers the sign-ins. Network and storage logs can come from AWS VPC Flow Logs, AWS and Cloudflare.
With Sazabi
Sazabi detects this today with no setup: the Sazabi agent automatically sets up sensors for your project and maintains them over time. Data Egress Alerts: Issues When One Actor Pulls Far More Data Than Usual covers what it catches.
Frequently Asked Questions
How do you detect data exfiltration?
Measure how much data each actor, host or key sends out and compare it to its own history. Flow logs, object-store access logs and application export events provide the numbers.
What logs show data exfiltration?
Application export events with row counts and bytes, VPC flow logs, object storage access logs and CDN logs. The key fields are the actor, the destination and the size.
How do I avoid false positives from backups and reports?
Tag scheduled exports and backups, allowlist the identity and destination, and compare other actors with their own median rather than a global limit.
Does compression hide exfiltration from bytes-based detection?
It can make response sizes smaller than the content. Log row counts or object counts next to bytes, and watch cumulative volume over an hour or a day.
Sources
- Exfiltration: the adversary is trying to steal data; data is often compressed and encrypted before removal (accessed Nov 8, 2026)
- VPC flow log records include bytes, srcaddr and dstaddr fields (accessed Nov 8, 2026)
- S3 server access logs include a Bytes Sent field (accessed Nov 8, 2026)
- CloudTrail data events record resource operations such as object-level API activity (accessed Nov 8, 2026)