Skip to content

Collect QuarantineEventsV2: UAC, Aftermath, Velociraptor

How to collect macOS QuarantineEventsV2, its -wal and -journal files, quarantine xattrs and .LastGKReject by hand or with UAC, Aftermath and Velociraptor.

Published on 6 min read

TL;DR. On a live Mac, the fastest collection is three commands from a Terminal with Full Disk Access: copy ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2* (the * brings the -wal and -journal files), dump quarantine attributes with xattr -r -l -x, and grab .LastGKReject if it exists. UAC, Aftermath and Velociraptor all collect the database; none of them collects quarantine attribute values, so add the xattr listing yourself. Hash first, work on copies.

What to collect

A complete quarantine collection has three parts:

  1. The database of every user: QuarantineEventsV2 plus its -wal and -journal companions. The companions can hold recent committed changes and older page copies, which is where deleted records survive (see recovering deleted records).
  2. The attribute values of files in the folders you care about: com.apple.quarantine and kMDItemWhereFroms. They carry the UUID that joins a file to its database row.
  3. .LastGKReject, Gatekeeper's record of the last item it refused. It may not exist, or may exist and be empty.

The easiest way: copy by hand on a live Mac

Open Terminal, make sure it has Full Disk Access, and run the commands below. Add sudo when you need to read other users' folders.

Current user

mkdir -p ~/qcase
cp -p ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2* ~/qcase/
xattr -r -l -x ~/Downloads ~/Desktop ~/Documents ~/Library/LaunchAgents > ~/qcase/xattr_$(id -un).txt 2>/dev/null

cp -p preserves timestamps and modes; the trailing * copies the database together with any -wal or -journal file. The xattr -r -l -x listing records every extended attribute as a hex dump, which keeps the exact bytes. ~/Library/LaunchAgents is in the list on purpose: a downloaded file sitting in an autostart folder is one of the leads worth checking.

All users

Run as root to copy every user's database into its own folder:

for u in /Users/*; do
  f="$u/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2"
  [ -f "$f" ] || continue
  d="$HOME/qcase/$(basename "$u")"
  sudo mkdir -p "$d" && sudo cp -p "$f"* "$d/"
done

Repeat the xattr listing for each user whose folders matter.

Gatekeeper's last rejection

The .LastGKReject file has lived at two paths in Apple's sources, so try both:

for f in /private/var/db/.LastGKReject /private/var/db/SystemPolicyConfiguration/.LastGKReject; do
  [ -f "$f" ] && sudo cp -p "$f" ~/qcase/"$(basename "$(dirname "$f")")_LastGKReject"
done

Only the last rejection is kept, and the file may be missing. It can also exist without any rejection in it: on one live macOS 26.6 system, /private/var/db/.LastGKReject was absent and /private/var/db/SystemPolicyConfiguration/.LastGKReject was a small XML property list holding an empty dictionary. Quarantine Parser reports that case as "no rejection recorded". What the file contains is covered in .LastGKReject as Gatekeeper evidence.

UAC

UAC (Unix-like Artifacts Collector, github.com/tclahr/uac) has an artifact files/system/quarantine_events.yaml that collects %user_home%/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2. The ir_triage and full profiles include it, because they include files/system/*.

sudo ./uac -p ir_triage /tmp
sudo ./uac -a ./artifacts/files/system/quarantine_events.yaml /tmp

The first command runs the whole triage profile, the second only this artifact. Output is uac-<hostname>-macos-<timestamp>.tar.gz by default (-f zip for a ZIP). UAC does not collect xattr values, so run the xattr -r -l -x command above as well.

Aftermath

Aftermath (Jamf, github.com/jamf/aftermath) runs with:

sudo ./aftermath

Output goes to /tmp by default; -o chooses another location. Aftermath copies each user's database to Artifacts/raw/lsquarantine_<username>, without the -wal. Its file metadata lists xattr names and kMDItemWhereFroms, not quarantine values. Again, add an xattr listing if the attribute values matter.

Velociraptor

Two approaches, depending on what you need:

  • Parsed on the endpoint. The MacOS.System.QuarantineEvents artifact queries the database on the endpoint and returns the columns DownloadTime, DownloadURL, Origin, AgentName, AgentBundle, User and EventUUID. Its default glob is /Users/*/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2. This is quick, but you only get what the query returns: no free space, no companions.
  • Raw files. Use Generic.Collectors.File with Root / and a Glob such as Users/*/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2*. The trailing * brings the companions, and you keep the free space that recovery needs.

If you deal with ZIPs made by Finder, MacOS.Forensics.AppleDoubleZip reads the __MACOSX AppleDouble entries they contain.

mac_apt and Plaso

mac_apt's QUARANTINE plugin parses both the database and .LastGKReject. Against a mounted image:

python mac_apt.py -o out MOUNTED /Volumes/evidence QUARANTINE

Against a single file:

python mac_apt_artifact_only.py -i com.apple.LaunchServices.QuarantineEventsV2 -o out QUARANTINE

Plaso also has an ls_quarantine SQLite plugin, useful when the database goes into a broader super-timeline.

Gotchas

Full Disk Access and TCC

macOS privacy protections (TCC) can stop Terminal from reading user folders. Grant Full Disk Access to the Terminal you use before collecting; otherwise errors are easy to miss, especially with 2>/dev/null hiding them. Check that the copied files are not empty.

WAL and journal companions

A database copied without its -wal can miss committed changes that have not been checkpointed into the main file yet, and you lose the older page copies too. On the macOS 26.6 system observed, the database used rollback-journal mode, so a -journal file is the more likely companion. Collect whatever is there.

AppleDouble on exFAT

If files were copied to exFAT, FAT or SMB volumes, macOS stores their extended attributes in AppleDouble ._name files. Collect those ._ files too: they can hold the quarantine value and WhereFroms of a file that left the Mac.

Hash first

Hash the collected files before any analysis and work on copies. Opening a database with sqlite3 can modify it (see recovering deleted records).

Extended attributes lost in transit

Extended attributes do not survive every trip. Copying to media without xattr support, or with tools that drop them, loses the values. The xattr -r -l -x text listing is the safest carrier: it is a plain file and survives any transport.

Loading the collection

Quarantine Parser accepts the UAC .tar.gz, the Aftermath archive or folder, and Velociraptor collection ZIPs as they are, as well as parsed MacOS.System.QuarantineEvents results in JSON lines and your own ~/qcase folder. Everything runs in the browser. The home page also has a copy-ready guide, How to get your data. For the meaning of what you collected, start with QuarantineEventsV2 forensics and com.apple.quarantine flags; a quick reference is on macforensics.app.

Frequently asked questions

Does the Terminal need Full Disk Access to copy QuarantineEventsV2?

Run the copy from a Terminal that has Full Disk Access, and add sudo for other users' folders. Without it, macOS privacy protections (TCC) can block reads in user folders and leave you with an incomplete collection.

Does UAC collect quarantine attributes?

No. UAC's quarantine_events artifact copies the QuarantineEventsV2 database, but UAC does not collect xattr values. Capture com.apple.quarantine values separately with xattr -r -l -x on the folders that matter.

Why copy the -wal and -journal files too?

They can hold changes that are not yet in the main file and older copies of pages, which is where deleted records survive. The trailing asterisk in the cp command copies them together with the database.

Can Quarantine Parser read a UAC or Velociraptor collection directly?

Yes. Drop the UAC .tar.gz, the Aftermath archive or folder, or a Velociraptor collection ZIP as it is. Everything is processed in your browser and nothing is uploaded.

Related articles