Reading view

There are new articles available, click to refresh the page.

Who decides to quarantine files?

Quarantine extended attributes, xattrs named com.apple.quarantine, aren’t attached to all files downloaded to Macs. Although once described as a voluntary scheme, putting files into quarantine is determined by a set of rules. This article explains how those rules work in macOS 26 Tahoe.

The default rule for apps that don’t run in a sandbox is that all new files they create don’t have a quarantine xattr attached to them. This is simple to verify by creating a new file using an app that hasn’t been obtained from the App Store, and isn’t one of Apple’s. Although it’s likely to get a MACL xattr attached, no quarantine xattr should accompany that. The same should also apply to files created by sandboxed apps, including TextEdit.

Info.plist

Although some processes and apps may explicitly attach quarantine xattrs, for example in AirDrop, this is a behaviour normally delegated to macOS by a setting in the app’s Info.plist, LSFileQuarantineEnabled. When that’s set to true, all files created by that app should bear the xattr. You can verify that by inspecting the Info.plist file in apps that download items from the internet, such as Safari, where it’s normally listed immediately below the app’s LSApplicationCategoryType.

No changes can be made to the Info.plist in a signed app, as those would break its signature.

CoreTypes.bundle

If that setting in Info.plist is false, or it doesn’t appear in the Info.plist, then there are additional and overriding settings contained in Exceptions.plist in the CoreTypes bundle, at /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources. That long list contains five dictionaries:

  • Additions, which assigns a lot of app categories, sets Java version requirements, and determines default settings for quarantine on files created by apps.
  • AppNapOverrides, which sets App Nap behaviours.
  • HighResolutionOverrides, which overrides High Res options for apps.
  • LaunchOverrides, which can disable specific version ranges of apps from being launched; these prevent older apps from being run.
  • MergeDocumentTypes, which merges some document types such as doc and docx for specific apps.
  • Overrides, which can override other settings.

Included in the Additions dictionary you should find overriding settings for the popular BitTorrent client Transmission, reading:
<key>org.m0k.transmission</key>
<dict>
<key>LSApplicationCategoryType</key>
<string>public-category.internet</string>
<key>LSFileQuarantineEnabled</key>
<true/>
</dict>

Referring to the app by its ID of org.m0k.transmission, the first of those assigns the app to an app category of public-category.internet, then sets the app to attach the quarantine xattr to all documents that it creates, including everything that it downloads.

Among the existing overrides in Tahoe, for example, are org.pythonmac.unspecified.BitTorrent and org.xlife.Xtorrent, to ensure that Transmission, Xtorrent and PythonMac BitTorrent clients should write quarantine xattrs to all their downloaded files. Although this Exceptions property list doesn’t cover every client, it should ensure that most do protect their downloads by attaching a quarantine xattr.

The CoreTypes bundle isn’t in the Signed System Volume of macOS, but is protected from change. Thus, there’s no way the user can alter which apps add the quarantine xattr to new files they create.

Mach-O binaries

I don’t know how this system works with command tools, which are single file executables. They can have an Info.plist embedded in the executable, but this is rare unless they need to be notarized. The most popular tool for downloading files from the internet must be curl, used in commands of the form
curl [URL] -o [localfile]
to download the file named in the URL to a local file named localfile. It’s simple to demonstrate that the download then doesn’t have any quarantine xattr attached to it, and those don’t gain the xattr when extracted from archives either.

While this does offer the user a way to download files that don’t have any quarantine xattr attached, it’s also almost universally used for the same purpose by malicious software.

Summary

  • By default, apps don’t normally attach the quarantine xattr to files they create.
  • Most apps that can download files from the internet opt to attach the xattr by setting LSFileQuarantineEnabled to true in their Info.plist.
  • Some of those that don’t, have that overridden in the Additions dictionary of Exceptions.plist in CoreTypes.bundle.
  • One notable exemption is the command tool curl, which is also used by malware to escape quarantine.

Quarantine, MACL and provenance: what are they up to?

Over the last few years, files and apps on our Macs have started to bristle with unfamiliar extended attributes (xattr). The oldest is the quarantine xattr, containing the quarantine flag, dating back to the introduction of Gatekeeper in 2012. Although its primary purpose is to determine which apps should undergo first run checks, it’s also to be found on many files. Then in macOS Catalina, the MACL xattr appeared and now seems to get attached to pretty well everything, no matter where it has come from. It was joined by the provenance xattr in macOS Ventura, and that too is spreading like wildfire on both apps and files. This article reviews why they’re there, and what you can do about them.

Quarantine

Since its introduction, Gatekeeper has drawn a distinction between apps that originated outside the Mac, and those that can be fully trusted, when performing security assessments on the first occasion. To enable that, apps that download items from the internet, or transfer them from another system on the same network, attach a quarantine xattr to every file that arrives on your Mac. When archives are decompressed, for example, the quarantine xattr is propagated to every file they contain. Gatekeeper then performs full first run checks on those apps, and in the right circumstances they may be run in translocation.

This com.apple.quarantine xattr is also attached to non-executable files, where its role isn’t clear, as they aren’t checked by Gatekeeper, and their quarantine flag isn’t cleared after they have been opened for the first time. However, you’ll find them on all items that have been downloaded by an app or tool that attaches them. As this xattr isn’t protected in any way, it’s straightforward to remove, although you should avoid doing so for apps whose origins could be suspicious, as that would prevent Gatekeeper from running its additional checks.

MACL

This is thought to be an abbreviation for Mandatory Access Control List, and might be intended to preserve privacy while allowing the user to open files. The com.apple.macl xattr is now probably the most common of all, as these get attached to any and every file, including apps, even if they were created on that Mac and never left its local storage.

This xattr contains 72 bytes of what could be two UUIDs, or just binary data. However, it’s protected by SIP, preventing any user from stripping it. This can be responsible for problems, for example files that can’t be opened in their default editor app, and some that can’t be saved. In the past one way of triggering this blocking behaviour was to set a document to be opened by default using an app other than its normal app, then saving it from that app before trying to open it again.

Perhaps the simplest way to remove this xattr is to copy the file to another volume, where the xattr is no longer protected by SIP, stripping it using my free editor xattred or the xattr command tool, then copying that back to its original location. Although it’s likely to be given another MACL xattr shortly, that should be less prone to cause problems.

Provenance

Most recent versions of macOS have what’s known as a Provenance Sandbox that enables the security system to track the origins of files, and trace which app has altered them. This has recently been detailed in full in Koh M. Nakagawa’s account of XProtect Remediator. It operates quite differently from the regular app sandbox, and doesn’t appear to impose any restrictions.

Apps that aren’t signed by Apple are assigned an 11-byte integer when they first clear Gatekeeper’s checks, and those are entered into the Provenance Tracking table in the ExecPolicy database, and attached to the app in the com.apple.provenance xattr. When that app performs operations like opening a file in write mode, or creating a new one, the same xattr with that app’s provenance ID is attached to the file. Thus, by checking the provenance ID on any file with the xattr, the app that last wrote to the file can be identified.

Provenance IDs and xattrs aren’t assigned to Apple’s own apps, or those installed from the App Store, but they are to apps that are signed using certificates other than Apple’s, and those that are notarised. When a file is created or changed by an app without a provenance ID, no xattr is attached to that file, and any existing xattr is left unchanged.

This is a powerful tool in gathering security intelligence. For example, suppose a Mac has just installed previously unknown malware that started to write files in one of the locations watched by behavioural XProtect under one of its Bastion rules. Those could be inspected, perhaps by one of the scanning modules in XProtect Remediator, the provenance ID checked against details in the Provenance Tracking table, and information forwarded to Apple for further investigation.

Evidence so far suggests that you don’t want to try to tamper with the provenance xattr, as it doesn’t appear to have any role in blocking access to files, and is working on our side. Like the MACL xattr, it’s now normally protected by SIP, so can’t be removed directly.

Summary

  • com.apple.quarantine is likely to be found on any app or file downloaded or transferred from another system, but appears harmless.
  • com.apple.macl is likely to be attached to most apps and files, even those that have remained local at all times. It can sometimes cause problems including blocking the file from being opened or saved, but is hard to remove as it’s protected by SIP.
  • com.apple.provenance is used to track which app has created or modified files. This can be important in security intelligence, so shouldn’t be removed, although it appears harmless and is working for our benefit.

Last Week on My Mac: The mystery of Safari’s Web Archives

It’s both a joy and a curse that so many tell me of bugs they encounter. The joy is that it enables me to investigate and report them here, but the curse is when I can’t reproduce the problem. This week’s curse has been Safari’s webarchives, a topic that I had wisely avoided for several years. Search this blog using the 🔍 tool at the top right of any page and you’ll see just four articles here that mention webarchives, and this is now the second in the last ten days.

While I’m writing about searching this blog, I should point out that tool doesn’t take you out to Google or any general search engine, but confines its scope to articles published here. Although precious few seem to use it, I find it invaluable when preparing articles, and strongly recommend it.

Not only had I avoided tackling this topic, but I see from my own local search that I have seldom used webarchives myself, although not as a result of any unreliability.

In principle, Safari’s webarchives should rarely cause a problem. They’re written by converting what Safari already holds in memory for a webpage into an XML property list, a process termed serialisation, and used effectively by a great many apps in more challenging circumstances. There may be occasions when this doesn’t quite work right, and it does require Safari to retain backward compatibility to ensure it can load and display property lists written some years ago. But by and large it should prove robust.

In practice, there are quite a few who appear unable to get this to work with many versions of Safari, yet I can’t repeat that here. For one reader, the most recent version of Safari that can reliably open their webarchives is 18.6, which is the only version I have experienced problems with. Running in macOS Ventura 13.7.8 here, that version appears unable to open the webarchives it creates, or those from later versions of Safari. Meanwhile Safari 26.1 running in macOS 26.1 has no trouble opening any webarchive I’ve tried from 2009 onwards.

For the last three years, Safari and its supporting libraries including WebKit have been provided to macOS in a cryptex, where they can’t be modified. The only way the user can go beyond Safari’s settings to change its behaviour is using Safari Extensions, which are controlled by Apple. There doesn’t appear to be any way for the user to prevent WebKit and Safari from loading webarchives correctly, intentionally or inadvertently.

Cursed by my inability to reproduce the problems reported, I have immersed myself in a couple of lengthy log extracts. One documents Safari 18.6 failing to open a webarchive it created, the other shows Safari 26.1 successfully opening the same webarchive.

Safari 18.6 seems to have been making good progress opening the webarchive until it came to loading the main frame. It then needed PolicyForNavigationAction before it could go any further:
01.154639 com.apple.WebKit Loading Safari WebKit 0x14c19b818 - [pageProxyID=21, webPageID=22, PID=596] WebPageProxy::decidePolicyForNavigationAction: listener called: frameID=24, isMainFrame=1, navigationID=26, policyAction=0, safeBrowsingWarning=0, isAppBoundDomain=0, wasNavigationIntercepted=0
01.154642 com.apple.WebKit Loading Safari WebKit 0x14c19b818 - [pageProxyID=21, webPageID=22, PID=596] WebPageProxy::receivedNavigationActionPolicyDecision: frameID=24, isMainFrame=1, navigationID=26, policyAction=0
01.154666 com.apple.WebKit Loading Safari WebKit 0x14c19b818 - [pageProxyID=21, webPageID=22, PID=596] WebPageProxy::isQuarantinedAndNotUserApproved: failed to initialize quarantine file with path.
01.154666 com.apple.WebKit Loading Safari WebKit 0x14c19b818 - [pageProxyID=21, webPageID=22, PID=596] WebPageProxy::receivedNavigationActionPolicyDecision: file cannot be opened because it is from an unidentified developer.
01.154799 Error Safari Safari Web view (pid: 596) did fail provisional navigation (Error Domain=NSURLErrorDomain Code=-999 "(null)")

So loading the main frame was halted with those chilling words “file cannot be opened because it is from an unidentified developer”, with which we’re only too familiar. The webarchive was in quarantine, it seems, and that put a stop to its loading. Only that isn’t quite accurate: there was no com.apple.quarantine xattr present, but one of those ubiquitous com.apple.macl xattrs instead. Safari had been stopped by its own security, didn’t even have the courtesy to inform us, and just sat there with an empty window going nowhere.

Safari 26.1 shows how it should have been done:
00.740168 com.apple.WebKit 0xa4bda0718 - [pageProxyID=19, webPageID=20, PID=1035] WebPageProxy::decidePolicyForNavigationAction: listener called: frameID=4294967298, isMainFrame=1, navigationID=25, policyAction=Use, isAppBoundDomain=0, wasNavigationIntercepted=0
00.740172 com.apple.WebKit 0xa4bda0718 - [pageProxyID=19, webPageID=20, PID=1035] WebPageProxy::receivedNavigationActionPolicyDecision: frameID=4294967298, isMainFrame=1, navigationID=25, policyAction=Use
00.740233 com.apple.WebKit 0xa4bda0718 - [pageProxyID=19, webPageID=20, PID=1035] WebPageProxy::receivedNavigationActionPolicyDecision: Swapping in non-persistent websiteDataStore for web archive.

From then, WebKit moves apace and the archived webpage is soon displayed.

This doesn’t of course mean that Safari’s failures to open and display webarchives successfully are all the result of NavigationActionPolicyDecisions that the webarchive can’t be opened because of this security problem, but I suspect this isn’t the only time this has occurred. The vagaries of com.apple.macl xattrs are well known, and their propensity to cause other innocent actions to be blocked is only too familiar. Unfortunately, the only reliable workaround is to knock a hole through macOS security by disabling SIP. But for this to happen without any information being displayed to the user is unforgivable.

Other apps that access Safari’s webarchives don’t appear tainted by this behaviour. Michael Tsai of C-Command Software tells me that his EagleFiler app hasn’t had such problems since its introduction in 2006. If you’ve been struggling to open webarchives in Safari, you might like to consider whether that could address those problems. In the meantime, I can see what I’ll be doing over Christmas.

I’m very grateful to Michael Tsai of C-Command Software for information and discussion.

Is Tahoe quicker to launch apps first time?

One of the longstanding oddities in macOS security has been scanning of a notarized app by XProtect before it can be launched. When apps are submitted to Apple for notarization, they’re scanned for malicious content using methods at least as effective as XProtect, and should any notarized software subsequently be identified as malicious, its notarization and signature are revoked immediately. That should make it impossible for any app with a valid notarization ticket to contain malware known to Apple.

One of the improvements believed to be incorporated into macOS 26 Tahoe is that validly notarized apps are no longer scanned by XProtect. When I examined this recently, I confirmed that was correct, although in practice this did little if anything to improve the launch times of apps. This article extends those observations to include app first run, when detection of malware is most critical.

When an app is run for the first time in a recent version of macOS, there are three options:

  • apps that aren’t quarantined, including those signed by Apple and almost all of those supplied through the App Store, normally don’t undergo additional checks;
  • quarantined apps that have been installed correctly undergo full first run checks, that have previously included XProtect scans;
  • quarantined apps being run from the immediate location they arrived in not only undergo full first run checks, but are additionally moved to be run from a random path in what’s commonly known as app translocation, or Gatekeeper Path Randomisation (GPR).

This article considers the second and third of those.

Quarantined first run, no translocation

In Sequoia 15.7 these apps undergo a “direct malware and dylib scan” using the XProtect data stored in its new location, in /var/protected/xprotect/XProtect.bundle. Because this is the first run, once Gatekeeper assessment is complete and confirms the app is safe to run, the user is presented with a dialog asking for their consent. Because of the inevitable delay in responding to that, two times can provide meaningful estimates of performance:

  • the time between the log entry reporting that Gatekeeper is performing a scan (“GK performScan”), and declaring the Gatekeeper scan complete (“GK scan complete”), in this case 5.35 seconds;
  • the time between the start of the XProtect scan (“Xprotect is performing a direct malware and dylib scan”) and the declaration of scan results (“GK Xprotect results”), here 5.33 seconds.

In Tahoe 26.0 no XProtect scan was attempted, as com.apple.xprotect entered in the log “Xprotect is skipping executable assessment”, and com.apple.syspolicy.exec confirmed “Skipping XProtect scan on seen software”. Despite that, the first of those times was nearly twice that required in Sequoia, at 10.29 seconds. The reason for this is unknown, but over that period the log contained about 13,000 entries reporting “SecKeyVerifySignature”.

As a result, a smaller and simpler app was used to test app translocation and its effects.

Quarantined first run, with app translocation

Instead of using Calibre as my test app here, I chose my own app Podofyllin, with its 442 KB executable and no dylibs or other complications. This was downloaded from here, unarchived automatically in the ~/Downloads folder and there run from the folder it came in, to ensure that it would be translocated.

Early in the launch sequence, com.apple.securityd writes a log entry indicating it has created the translocation directory “SecTranslocateCreateSecureDirectoryForURL”, following which diskarbitrationd replicates the app bundle to what appears as a different volume in the translocation path. Then a first run Gatekeeper assessment is performed, including an XProtect scan, checking the notarization ticket using CloudKit, a user approval dialogue, and setting up the app’s provenance tracking.

In Sequoia 15.7, the XProtect scan took 0.15 seconds, and the total period required for the Gatekeeper scan was 0.19 seconds.

In Tahoe 26.0, com.apple.syspolicy.exec logged “Skipping up front XProtect scan” and com.apple.syspolicy went straight on to perform the CloudKit lookup. This was confirmed later by com.apple.syspolicy.exec in “Skipping XProtect scan on seen software” just before reporting the Gatekeeper scan was complete. With no time required for the XProtect scan, the total used for the Gatekeeper scan was 0.16 seconds, 88% of that for Sequoia.

Stuck in translocation

Over the last couple of years it has become clear that some apps, even though they have been moved from their original download location, continue to undergo translocation whenever they’re run, and that can cause ongoing problems.

An app will be translocated if all the following apply:

  1. the app has a com.apple.quarantine extended attribute attached;
  2. the app must be opened by Launch Services (normally the Finder) rather than a command shell;
  3. the app hasn’t been individually moved in the Finder from the folder it was unarchived or downloaded to, wherever that was.

Tests in recent macOS show that apps won’t be translocated if:

  • they have no com.apple.quarantine extended attribute, or it has been removed;
  • they have been moved individually in the Finder so they’re now enclosed in a different folder.

The following will normally result in the app being run in translocation:

  • opening the app in the folder that it first arrived in, even if that folder has been moved elsewhere, such as into an Applications folder;
  • moving the app at the same time as other apps, even if they’re all put into an Applications folder. Group or simultaneous moves in the Finder aren’t counted as a move that will stop future translocation;
  • running the app again without moving it from a location from which it has already been translocated. Until the app is moved from that location, it’s likely to be repeatedly translocated every time that it’s run.

You can readily check whether an app is being run in translocation by starting the app and either:

  • inspecting that app in Activity Monitor, by selecting it in the CPU view and clicking on the ⓘ tool,
  • running ps xw | grep AppName in Terminal.

If the path shown for the app is something absurdly long like /private/var/folders/x4/[random chars]/T/AppTranslocation/[UUID]/d/, then it has been translocated.

If an app that appears to have been correctly installed is still being translocated, move it individually (one app at a time) from the folder it’s currently in to a different folder, run it from there, close the app, and move it back to where you want to keep it.

Conclusions

  • macOS 26.0 Tahoe skips reported XProtect malware scans when a notarized app is run for the first time in quarantine, even when it has been translocated.
  • Despite that, first run checks in Tahoe can still take significantly longer than in subsequent runs, although the reason for that isn’t clear from the log.
  • If an app doesn’t appear to run properly, check whether it’s stuck in translocation. If so, free it as explained above.

❌