/data/sensitive leave this machine, and if so, who sent it and to where?
Filetrace is built for exactly this. A file is named at the moment its bytes reach a socket, so the answer includes the process, the destination and the method, not just a byte count.
1. Ask for the files
--path matches the whole path, and * crosses /, so this covers the subdirectories too. The result is most-recently-active first; --sort bytes puts the largest first.
- The first line is a Python process that read a spreadsheet and then sent it:
INFERRED, with the script that did it. That is the shape of an application upload. - The second line is
sendfileandEXACT: the kernel handed the file to the socket directly. A command-line tool sent a private key.
2. Narrow with the filters that matter
--remote selects a network to include; there is no negation. To find traffic outside a known network, list the transfers with --remote omitted and compare the DESTINATION column against the allow-list, or keep an alert on the file-egress rate in the metrics layer (below).3. Follow a hit with inspect
When one file matters, ask about the file itself:
inspect process <pid> shows everything that process is sending now. From an address, inspect ip 203.0.113.25 --since 24h shows which processes talk to it and which files were sent there.
4. Watch for new sends
watch ranks transfers by current rate, so a large upload stands out while it is happening. Add --file '/data/sensitive/*' to see only the files you care about, or --direction outbound on a busy server.
5. Alert on it
The observability recipes include ready-to-use rules. The two that fit here:FiletraceLargeFileTransferfires when one process sends more than 1 GB in five minutes.FiletraceUnattributedEgressfires when most egress has no file behind it, which is worth checking when uploads are the concern.
6. Keep the record
For an audit trail that outlives the agent, export thefile_transfer log records to a collector. Each record carries the path, the process, the script, the peer address and the bytes:
file_paths = false; the record keeps the device and inode, which still identify the file for an investigator with access to the host.
Where the answer can mislead
INFERREDis not proof. A thread read the file and then sent bytes on a socket; the bytes cannot be proven to come only from that file. Treat it as strong evidence and corroborate with the script and the destination.- Bytes counted are what the local socket accepted, not what the remote end acknowledged. A send that fails mid-way still shows the bytes the kernel accepted.
- Loss hides transfers. Check
filetrace_events_dropped_totaland the*marker. With loss, a file can be missing from the list entirely. - History is in memory. After an agent restart, past transfers are gone. Use OTLP or the metrics for anything that must persist.
- Encrypted or generated payloads read from memory have no file behind them and appear in
transfersasUNKNOWN, not infiles. Look atfiletrace transfers --include-unknowntoo.