The question was innocent enough. I wanted to know where a file sitting in my Downloads folder had come from. I couldn't remember its name, my browser history was long, and asking the file itself looked like the shorter path.
macOS has a place for exactly this. Downloaded files get an extended attribute called com.apple.quarantine, and LaunchServices keeps a SQLite ledger alongside it. I opened both. The ledger held 1,945 records, a tidy run from June 2025 to late last night. Then I looked at the address column: all 1,945 rows were empty.
That empty column pulled me into a two-hour measurement. Here is what came out of it: the quarantine mark is not what we think it is. It isn't a record saying "this file came from here"; it's a flag saying "this file needs the user's consent". And whether that flag survives into the next file is decided not by the operating system but by the code of whatever tool touches the file — I tried nine paths, five of them inherited the mark and four lost it silently.
Every measurement below comes from one machine at one moment: macOS 26.6.2 (25G83), arm64, counted on the morning of 2 October 2026. Both the ledger and the folder are live, so tomorrow's numbers will differ — what matters isn't the numbers but the relationships between them.
Reading the Mark: Four Fields, Zero Documentation
Checking whether a file carries the mark takes one command:
xattr -p com.apple.quarantine ~/Downloads/<file>
# 0281;6a8435e5;Chrome;B71407DA-5626-4ACB-8201-7A62855420FA
Four semicolon-separated fields: a flag number, a hexadecimal timestamp, the name of the app that applied the mark, and a UUID. Apple documents this string's format nowhere — I looked, and I didn't find it. But the LaunchServices quarantine properties are documented and map onto the fields one by one. For kLSQuarantineAgentNameKey the documentation says it is the app name of the quarantining agent, and adds that when the key is absent from the caller's dictionary, the agent name is set automatically to the current process name. That is why the third field reads Chrome.
Decoding the timestamp takes a single line:
python3 -c "import datetime;print(datetime.datetime.fromtimestamp(int('6abf42eb',16)))"
So far, familiar territory. What's interesting is whose job the mark actually is. I assumed quarantining a download happened automatically. It doesn't. The documentation for the LSFileQuarantineEnabled key puts it in one line: it is a Boolean saying whether files the app creates get quarantined by default. The mark is something the downloading app volunteers to apply.
Easy enough to test. I pulled the same file with curl:
curl -sS -o astro-logo.svg https://astro.build/favicon.svg
xattr -l astro-logo.svg
# com.apple.provenance:
No quarantine. Only com.apple.provenance, which I'll come back to. Chrome would have left a mark; curl doesn't, because curl isn't a member of that club. That was the first lesson: the absence of a mark doesn't tell you the file is safe, it tells you the tool that fetched it doesn't apply marks.
Volunteering isn't the only door, though. The system carries an exception list of its own that can override an app's Info.plist:
plutil -p /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Exceptions.plist \
| grep -c LSFileQuarantineEnabled
# 18
On this machine, eighteen bundle identifiers are forced to apply marks by the system even without carrying the key themselves — Firefox, Thunderbird, Transmission, Opera, Azureus and a few browsers that no longer exist. The file sits inside root-owned, signed system storage; a user can't edit the list. So you can't tell whether an app applies marks by reading its Info.plist alone. That half the list is decade-old dead software is its own detail: quarantine exceptions have piled up like a museum.
I scanned my own Downloads folder. Including subdirectories, 217 of 306 files carry a mark and 89 do not. The distribution of agent names shows who volunteers: Chrome 77, WhatsApp 45, Claude 42, Outlook 22, Preview 7, Excel 6, Word 2 — plus 16 files where the agent field is empty.
A 1,945-Row Ledger With Zero Addresses
The mark sits on the file, but there's a central ledger too:
sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 \
"SELECT count(*) FROM LSQuarantineEvent;"
# 1945
This 425 KB file has stored every quarantine event from 2025-06-26 11:50:06 to 2026-10-01 22:51:21. Broken down by agent, it's a more honest summary than browser history: Chrome 1031, Cyberduck 873, ChatGPT 21, Opera 9, Homebrew Cask 9, Atlas 2.
The schema cheered me up, because the columns I wanted were right there: LSQuarantineDataURLString and LSQuarantineOriginURLString. Their documentation is clear too — kLSQuarantineDataURLKey is the actual URL of the quarantined item, and kLSQuarantineOriginURLKey is the URL of the resource originally hosting it; for web downloads the page on which the user started the download, for attachments the email message or calendar event the item was attached to.
Then I counted:
sqlite3 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 \
"SELECT sum(LSQuarantineDataURLString IS NOT NULL),
sum(LSQuarantineOriginURLString IS NOT NULL),
count(*) FROM LSQuarantineEvent;"
# 0|0|1945
Zero. Zero. One thousand nine hundred forty-five. The columns exist, the schema is unchanged, the documentation still talks about URLs — and on this machine not one of fifteen months' worth of records stores an address. The file side has a similar gap: of the 277 top-level files, only 86 carry the com.apple.metadata:kMDItemWhereFroms attribute, so 69% of them have no "where from" information at all. (The mark ratio was counted over 306 files including subdirectories; I kept these two attribute scans to the top level, which is why the denominators differ.)
Putting the ledger next to the files opened a second crack. The agents marking files on disk include WhatsApp, Claude, Outlook, Preview, Excel and Word; none of those six appears in the ledger at all. The reverse holds too: Cyberduck wrote 873 events into the ledger and has not a single marked file in Downloads. Chrome is the only name on both lists. So writing an xattr onto a file and writing a row into the ledger are not the same job; they happen on separate paths, done by separate implementations. Seeing a mark and concluding "then there must be a ledger row for it" would be wrong for six applications on this machine.
I don't know why, and I'm not going to invent a reason. What I do know is what it means in practice: this ledger is not a forensic record. It tells you which app applied how many marks and when; it does not tell you that a given file came from a given address. If you're investigating a file's origin and leaning on this table, count the column first and confirm it isn't empty.
One note on opening it: don't write to the live database, copy it first and work on the copy. The timestamp is kept in the Core Data epoch, so making it readable needs datetime(LSQuarantineTimeStamp + 978307200, 'unixepoch', 'localtime').
I Tried to Decode the Flag Field, Then Stopped
That first number is very tempting. I had a ready-made sample, so I counted: 0281 on 71 files, 0087 on 42, 0083 on 39, 0081 on 30, 0283 on 18, 0082 on 13, 0287 on 2, 03c1 on one, 0086 on one.
In my own tests I saw a pattern. When I hand-wrote 0083 onto an archive and extracted it, the files that came out read 0283 every single time — the 0x0200 bit added, the agent field cleared, the UUID preserved. (The timestamp sometimes matched the source's and sometimes carried the current moment; I couldn't pin down which is chosen when, so I'm not writing a rule for it.) "Fine," I said, "0x0200 marks an inherited mark." It was a nice hypothesis. Then I tested it in the field: of the 92 files carrying the 0x0200 bit, 76 have a non-empty agent name. If an inherited mark is supposed to clear the agent, those 76 files refute the idea. The other direction held perfectly, though: all 16 files with an empty agent field carry 0x0200. A one-way relationship isn't enough to write a rule on, but it's worth noting.
So I stopped there. Apple doesn't document these bits, and I'm not going to write up a pattern derived from three measurements as if it were a rule. The practical takeaway still holds: don't build policy on the flag field. Whether a file is marked is reliable information; trying to read the mark's subtext means reverse-engineering an undocumented binary format that can change quietly in the next release.
Who Carries the Mark, and Who Drops It
This was my real question. When you extract a marked archive, do the files inside inherit the mark?
I set the experiment up cleanly: packed a small two-file directory as zip, tar.gz and uncompressed tar, applied the same mark to all three by hand, then opened or copied them nine different ways.
Q="0083;$(printf '%x' $(date +%s));SafariTest;$(uuidgen)"
xattr -w com.apple.quarantine "$Q" package.zip
unzip -q package.zip -d A
xattr -p com.apple.quarantine A/package/a.txt
# 0283;6abf42eb;;DCC5A817-FC07-440B-AF95-0BDEEB1405C7
The results came out sharper than I expected:
| Path | Mark inherited? |
|---|---|
unzip -q package.zip |
Yes (0283) |
ditto -x -k package.zip B |
Yes (0283) |
tar -xf package.tar |
Yes (0283) |
tar -xf package.zip (bsdtar reads zip) |
Yes (0283) |
cp package.zip copy.zip |
Yes (0283) |
| `gzip -dc package.tgz \ | tar -xf -` |
cat package.zip > new.zip |
No |
dd if=package.zip of=new.bin |
No |
rsync package.zip new.bin |
No |
I tried Python too, in three different orders: open the input before creating the output, do the reverse, create a second file in the same process. The mark survived none of them. I repeated the plain read-then-write case separately with Apple's /usr/bin/python3 and with the python.org 3.13 build — both produced an unmarked file.
That table settles one thing: inheritance is not an automatic behavior of the file system or the kernel. If it were, cat and cp would behave the same way — both read the same file given by name, and one carries the mark while the other doesn't. What separates them is the tools' own code: unzip, ditto, bsdtar and cp implement inheritance, while cat, dd, rsync and Python just move bytes.
Two conditions have to hold at once, and bsdtar demonstrates that by itself: the same tool appears on both sides of the table. tar -xf package.tar carries the mark and gzip -dc package.tgz | tar -xf - doesn't — because in the second case the archive arrives as a stream, so there is no source file and therefore no attribute to read. The tool has to know about inheritance and have a named source to read the mark from. (The rsync row was measured with openrsync, this machine's default, with no extra flags; results may differ with flags that carry xattrs.)
One detail stands out: cp does not copy the mark verbatim. The source reads 0083;…;SafariTest;UUID while the copy reads 0283;…;;UUID. So the attribute isn't being duplicated, it's being rewritten by the system. The same thing happens to files coming out of archives.
Apple's 2026 Patch List Includes These Four Tools
After building the table I went to Apple's security notes, mostly to check whether my measurement was still current. The answer both supported the table and showed its limits.
The macOS Tahoe 26.5 notes (11 May 2026) carry three entries: CVE-2026-28849 in the BOM component, CVE-2026-28900 in libarchive, CVE-2026-28914 in zip. All three describe the same impact: a maliciously crafted ZIP archive may bypass Gatekeeper checks. The descriptions differ, though — the line about a file quarantine bypass being addressed with additional checks appears in only one of the three, the libarchive entry. The same release closes a similar bypass via disk images in the Kernel (CVE-2026-28954), and that entry carries the same description.
The 26.7 notes (14 September 2026) add CVE-2026-65399 in the copyfile component: an archive may be able to bypass Gatekeeper. The same release also closes Gatekeeper or sandbox bypasses in CoreServices, the Kernel, and a component named quarantine outright.
Now lay the two lists on top of each other. The four tools that carried the mark in my measurement: ditto (BOM), bsdtar (libarchive), unzip (zip), cp (copyfile). All four are among the components Apple patched during 2026. That's no coincidence — because inheritance is implemented by the tools, the bugs live in the tools too; every archive format is a separate implementation and a separate bypass surface.
But Apple's list is longer than my table, and that's information in itself: the same two releases patched the Kernel, CoreServices and quarantine as well, and one bypass came through disk images. The quarantine bypass surface doesn't end with archive tools. The table above covers only its most hand-testable part.
What this means in practice: this chain working correctly depends on your OS version. This machine runs 26.6.2, so the copyfile fix isn't in this kernel — which also means the cp row was measured against an unpatched copyfile, and I haven't confirmed it behaves the same on a patched 26.7. If you have a workflow that relies on mark inheritance, staying current isn't a comfort, it's a precondition of the mechanism.
What the Mark Actually Blocks
So far I've looked at how the mark travels. But what does being marked actually do?
The Gatekeeper documentation says it plainly: approval is requested the first time downloaded software is opened, so that nobody is tricked into running executable code they took for a plain data file. The approval path is spelled out too: System Settings, Privacy & Security, "Open Anyway".
I pictured a click-through dialog. Measuring it from the terminal, I met something much harsher. I compiled a three-line C program, left one copy clean and marked the other:
clang -o t1 y.c && cp t1 t2
./t1 # BINARY RAN, exit=0
xattr -w com.apple.quarantine "$Q" t2
./t2 # no output, exit=137
xattr -d com.apple.quarantine t2
./t2 # BINARY RAN, exit=0
137, that is 128+9: SIGKILL. The same binary, the same file system, one attribute of difference. With the mark the process is killed before it starts running; remove the mark and it comes back. No dialog, no warning, no error message — I went looking with log show and found nothing: a three-minute window, --info --debug on, predicates covering process == "kernel", the AMFI sender image and the syspolicy subsystem. There may be lines a non-root log show can't see; if someone can surface them, the method is right here and easy to refute. If anyone has spent hours wondering why a marked binary dies silently when called from a script, the answer is here.
Two more tests, both instructive.
I marked a copy of Apple-signed /bin/echo: it died with exit=137 as well. So the rule isn't "unsigned binaries"; once something stops being a system binary, any unapproved executable is refused while the mark is on it.
Then I put the same mark on a shell script:
printf '#!/bin/sh\necho "SCRIPT RAN"\n' > x.sh && chmod +x x.sh
xattr -w com.apple.quarantine "$Q" x.sh
./x.sh # SCRIPT RAN
sh x.sh # SCRIPT RAN
Both ran. A marked script meets no resistance at all, because the thing being exec'd isn't the script, it's /bin/sh. For a plain binary launched straight from the terminal, the gate stands in front of the Mach-O; interpreted code never walks through it. That isn't the same as saying the mark only concerns binaries — app bundles, pkg installers and disk images are separate paths, and the Kernel entry in 26.5 closes the disk image one precisely.
I owe a warning here: the fix for this section is not "delete the mark". For a binary you compiled yourself, xattr -d is reasonable; for one you distribute to other people, the right path is signing it, notarizing it, and attaching the ticket with xcrun stapler staple. Apple's notarization documentation says it plainly: when the user first installs or runs the software, the presence of a ticket tells Gatekeeper that Apple notarized it. Make mark-deletion your distribution strategy and you've asked your users to switch Gatekeeper off.
One more thing worth measuring: what does spctl say? I assessed two copies of a notarized app, one marked and one clean. Both returned accepted source=Notarized Developer ID, and --context kLSDownloadedFileContext didn't change the answer either. So spctl -a reports the state of the signature and the notarization, not the presence of the mark. You have to ask the two questions separately: spctl/codesign for the signature, xattr for the mark.
And the most open spot in the chain: curl … | sh never creates a file. There is no object to mark, so there is no consent to ask for. Gatekeeper has nothing to say on that path — which is not a flaw, it's the scope of the design.
What You're Deleting When You Clean Up
The internet is full of "if the mark is in your way, delete it" advice. Usually with xattr -cr, meaning all attributes at once. So I counted what goes, running xattr -c on a file with three attributes:
before: com.apple.metadata:kMDItemWhereFroms com.apple.provenance com.apple.quarantine
after : com.apple.provenance
The quarantine went, and the "where from" information went with it. So in removing the mark you also remove the only origin record you had — the very record that's already missing on 69% of files. If your goal is to clear the mark, xattr -d com.apple.quarantine takes exactly one attribute; -c sweeps the floor.
The interesting part is that com.apple.provenance isn't removed. It was on the file I pulled with curl, and it's on 193 of the 277 files in Downloads. I couldn't find any Apple documentation for this attribute, so I won't make claims about what it holds; all I'm noting is that it's more widespread than quarantine and that xattr -c can't remove it.
A Half-Hour Check on Your Own Machine
If you want to run the same measurements yourself, here's the order:
- Count how many files in your Downloads folder are marked. If the ratio isn't 100%, you have tools that don't apply marks either — the agent field tells you which.
- Count the rows in the ledger and check whether the address columns are populated. If you plan to investigate origins, know in advance whether you're leaning on an empty column.
- Check your version with
sw_vers. The quarantine bypasses in the 26.5 and 26.7 notes concern archive paths; if you rely on mark inheritance, being current is part of the mechanism. - If your build or deployment pipeline extracts archives, choose the tool deliberately. A
tarfed through a pipe drops the mark — sometimes that's exactly what you want, but don't let it happen by accident. - If you need to clean a mark, use
-d, not-c. - If the machine belongs to a fleet, some of these decisions may not be yours: the Gatekeeper documentation notes that users can override the policy and open any software unless a device management service restricts that. Don't assume the behavior you measure on your own machine will hold on a managed one.
And one habit to avoid: treating the absence of a mark as a trust signal. Eighty-nine of my files are unmarked, and not one of them earned that by passing a check; the tool that fetched them simply didn't apply one.
The Mark Is a Question, Not an Address
I started this measurement wondering where a file came from, and I never got an answer to that question. What I got was more useful: I learned not what the quarantine mechanism is, but what it isn't.
Quarantine is not an origin record. It's a note an app leaves saying "I brought this in, let the user approve it once". Leaving the note is voluntary, carrying it is the tools' business, the ledger keeps no addresses, the only thing it blocks is executable binaries, and when it's removed no trace remains.
What does knowing that change? One general habit around security mechanisms: don't treat the presence of a flag as proof that a check was performed. The mark is a question mark, not a certificate. Black boxes spend their worst nights without telling anyone; this particular box at least confesses what it doesn't do, as long as you count.
Incidentally, there's another example of this machine's own ledgers misleading me: launchd tried 21,881 times and I never looked once. The counters are right there, and nobody reads them.
Official Sources
- Apple Platform Security — Gatekeeper and runtime protection in macOS
- Apple Support — Safely open apps on your Mac
- Apple Developer — LSFileQuarantineEnabled
- Apple Developer — kLSQuarantineAgentNameKey
- Apple Developer — kLSQuarantineOriginURLKey
- Apple Developer — kLSQuarantineDataURLKey
- Apple Developer — Notarizing macOS software before distribution
- Apple Support — About the security content of macOS Tahoe 26.5
- Apple Support — About the security content of macOS Tahoe 26.7
Top comments (0)