Sandboxing makes quarantine flags almost meaningless

The quarantine flag, an extended attribute (xattr) of type, used to be one of the most meaningful and important of all the xattrs attached to files. It meant that item had been downloaded from the Internet. In the case of apps, it’s used to determine whether that app needs to undergo full first-run checks by Gatekeeper before being allowed free run on your Mac.

Quarantine for apps

This works quite cleanly: the xattr contains the flag itself as a Gatekeeper score, the system time of download, the downloading app or agent, and a UUID for that quarantine event. It’s not only a remarkably sticky xattr which is seldom lost or removed, but it propagates through the contents of archives when they are unpacked. This ensures that, no matter how an app is delivered from the Internet, it retains the quarantine xattr to ensure that it undergoes full first-run checks.

Although this xattr is encoded as UTF-8 text, the Gatekeeper score is interpreted in terms of binary flags. It’s the second of these which carries the bit to indicate first-run checks. When first set, every file in an app or document might carry a score of 00 83, which is
00000000 10000011
in binary. After a successful first run, in which an app clears Gatekeeper’s checks and is run by the user, that changes to 00 C3, which is
00000000 11000011
The bit set there indicates successful completion of Gatekeeper’s checks. In earlier versions of macOS, a lower order bit would also be set to indicate that the app has been run that first time:
00000000 11100011
but that practice appears now to have been discontinued.

Although completion of Gatekeeper’s first-run checks changes the Gatekeeper score on the app folder itself and executable code within it, other non-executable files within the app bundle such as the Info.plist and resources such as HTML files don’t have any changes made to their quarantine xattrs.

The UUID matches an entry in the QuarantineEvents SQLite database in ~/Library/Preferences/ which can be used to confirm the quarantine status too. However, experience shows that neither the downloading agent nor the QuarantineEvent are routinely checked by Gatekeeper.

Although most commonly known in apps for Gatekeeper’s purposes, all downloaded files should be given a quarantine xattr, unless the tool which downloaded them bypassed this system; the widely-known example of such byassing is curl, which is consequently used by malware too. When downloaded by a well-behaved agent such as Safari, documents have essentially identical xattrs attached to them as quarantine flags.

Quarantine for the sandbox

Since Apple introduced sandboxing for apps, the quarantine xattr has been used for a quite different purpose: to flag which document files have been opened by sandboxed apps. This first became prominent in High Sierra, when many users reported the appearance of these flags on documents which had never left the safety of their Macs, and in some cases appeared to cause problems, including lengthy scans of movies by QuickTime Player.

A careful look at this process reveals that this doesn’t only apply to documents which are saved by sandboxed apps, but to many documents which they merely open. Strip any quarantine xattr from a QuickTime movie, open it in QuickTime Player, close it without even playing, and you are likely to see a quarantine xattr added. The same applies to PDF documents opened in Preview.

This behaviour appears consistent across almost all apps which run in a sandbox, even if they’re not supplied by the App Store. One exception that I have found is the latest version of BBEdit: although sandboxed (and notarized), the non-App Store version doesn’t appear to attach quarantine xattrs to text files which it opens or writes, even when they are PDFs, for example. Apps which have been notarized but not sandboxed don’t behave in this way either.

For file types like JPEG, PNG, Movies and PDF, which are specific targets of this behaviour, the rules for attaching a quarantine flag by a sandboxed app appear to be:

  • Is the file locked? If so, no new quarantine xattr is written.
  • Does the file already have a classic quarantine flag, indicating it was downloaded from the Internet? If it does, that is left alone, and no new quarantine xattr is written.
  • Does the file already have a quarantine xattr written by the same app? If so, it is not replaced. The xattr’s datestamp therefore records the first time that the document was opened by that app, assuming that no other sandboxed app has opened it since.
  • In all other cases, a new-style quarantine flag is written to the file.

File types concerned appear to be those which have been associated with vulnerabilities in the past, but not generally plain text, although some types of text file are included in the scope. It makes no difference whether the document is in the Documents folder inside the app’s own Container, or out in another folder entirely, although Jeff Johnson associates this behaviour with security-scoped bookmarks.

In Mojave 10.14.4, the quarantine xattrs written follow a common pattern, and by previous standards are defective. Although they contain the Gatekeeper score, timestamp, and app or agent writing the xattr, they normally don’t contain any UUID, so cannot be entered into the QuarantineEvents database. Given their frequency, this is probably just as well. As a result, they are usually easy to tell apart from traditional quarantine xattrs, which are often 60 bytes or more in length. Sandbox quarantine xattrs are shorter, normally less than 50 bytes, although this varies according to the length of the app or agent’s name.


The standard Gatekeeper score used is 00 82, or in binary
00000000 10000010
which would normally be interpreted as indicating that Gatekeeper (or, as this is a document rather than an app, XProtect) checking is required. Unfortunately, inspecting the unified log hasn’t yet turned up any entry indicative of this process, which may be the result of the general dearth of sandbox-related entries, making it very hard to investigate further.

Inevitably, this behaviour has made quarantine xattrs among the most common extended attributes in macOS. Of just over half a million files scanned in my main Documents folder, over 125,000 or 25% now have quarantine xattrs attached, a large proportion of which are too small to be classic quarantine flags complete with UUID.

Although in theory attaching a quarantine xattr to a file shouldn’t have any functional impact, in practice some users find them very troublesome. Rich Siegel reports that many are finding that flagged scripts can’t be run in Terminal or using NSTask.

Workarounds aren’t easy to implement either. The best solution would be to strip quarantine xattrs, but that requires a command or an app such as my free xattred. As the next time that document is opened using a sandboxed app the quarantine xattr will be re-written, this can get tedious and frustrating.

This new practice of sandboxed apps writing quarantine xattrs to the documents which they’ve opened has potential value in forensic investigation, although as these events are only recorded the first time that particular app opens the document, and there’s no entry in the QuarantineEvents database, they need to be interpreted with care.

The unfortunate result is that the quarantine xattr, which used to mean only one thing, needs careful evaluation to see whether it is the result of a file being downloaded from the Internet, or simply one of the many local documents which have been opened by a sandboxed app. Do you remember what happened to the boy who cried wolf?

Thanks particularly to Jeff Johnson @lapcatsoftware who pointed out that this (ab)use of quarantine xattrs is due to sandboxing, and to Rich Siegel @siegel and Erik Schwiebert @Schwieb who confirmed and contributed additional information.