On February 9 I emailed Apple Product Security and reported a vulnerability that allows an app to bypass macOS privacy protections. I mentioned this the same day in a blog post. The vulnerability still exists in macOS 10.15 Catalina. Yesterday I learned that this vulnerability would not be eligible for Apple's Mac bug bounty program (because it was reported before the program was announced). Thus, I'm disclosing the vulnerability to the public today. Apple has had 8 months to address the vulnerability, and they've chosen not to address it. I believe that I've already gone above and beyond the duty of responsible disclosure by keeping my secret for so long. It's not even a particularly profound secret, for the vulnerability is hiding in plain sight, as you'll see.
The privacy protections of macOS are supposed to prevent applications from unauthorized access to certain directories that contain sensitive user data. On Mojave, these directories include ~/Library/Application Support/AddressBook
, ~/Library/Application Support/com.apple.TCC
, ~/Library/Calendars
, and ~/Library/Safari
. There may be other directories that I'm forgetting. You can't even list the contents of these directories in Terminal app unless Terminal has special permissions, such as Full Disk Access:
$ ls Library/Safari ls: Safari: Operation not permitted $ sudo ls Library/Safari Password: ls: Safari: Operation not permitted
Catalina has added more protected directories: ~/Desktop
, ~/Documents
, and ~/Downloads
.
The vulnerability I found is that macOS privacy protections are not respected by the File System Events API:
The file system events API provides a way for your application to ask for notification when the contents of a directory hierarchy are modified. For example, your application can use this to quickly detect when the user modifies a file within a project bundle using another application.
It also provides a lightweight way to determine whether the contents of a directory hierarchy have changed since your application last examined them. For example, a backup application can use this to determine what files have changed since a given time stamp or a given event ID.
An app without special permissions can register for notifications of file system events that occur in directories that are supposed to be protected. These file system event notifications can disclose private information that the app should not have access to. Here's some sample code illustrating how it works:
@implementation AppDelegate {
FSEventStreamRef _stream;
}
static void MyCallback(ConstFSEventStreamRef stream, void* clientCallBackInfo, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags* flags, const FSEventStreamEventId* eventIds) {
NSArray* paths = (__bridge NSArray*)eventPaths;
for (size_t i = 0; i < numEvents; ++i) {
NSLog(@"LOLCATS:%@", paths[i]);
}
}
-(void)applicationDidFinishLaunching:(NSNotification*)notification {
NSString* home = NSHomeDirectory();
NSLog(@"LOLCATS NSHomeDirectory:%@", home);
NSArray* pathsToWatch = @[home];
CFAbsoluteTime latency = 1.0;
FSEventStreamEventId sinceWhen = 0;
FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
_stream = FSEventStreamCreate(NULL, &MyCallback, NULL, (__bridge CFArrayRef)pathsToWatch, sinceWhen, latency, flags);
NSAssert(_stream != NULL, @"FSEventStreamCreate failed!");
FSEventStreamScheduleWithRunLoop(_stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
Boolean started = FSEventStreamStart(_stream);
NSAssert(started, @"FSEventStreamStart failed!");
}
@end
If you launch Console app, search for LOLCATS
, and run a non-sandboxed app with this code, you'll see… a lot.
There are limits to this vulnerability: an unauthorized app cannot read the contents of a file in a protected directory, and it cannot modify anything in a protected directory. But an unauthorized app can observe in real time — and also as far back in time as it likes — any file operations in protected directories, such as files getting created, modified, renamed, moved, or deleted. You can easily see why this is problematic on Catalina, because Desktop, Documents, and Downloads are supposed to be protected on Catalina, but an unauthorized app can see anything that happens (and has happened) there. It can see which files you download, for example. This is also true on Mojave and earlier, but Apple didn't claim that those particular directories were protected on Mojave and earlier.
When I wrote my blog post back in February, I tried to explain some of the consequences of the vulnerability without giving away the details of the vulnerability. You could say that I employed a bit of misdirection by choosing to focus on ~/Library/Safari
. I said, "a malware app could secretly violate a user's privacy by examining their web browsing history." How is this possible with file system events? If you look inside the directory ~/Library/Safari/LocalStorage
, you'll see that Safari saves local storage files that are named after their associated web sites, for example, https_www.apple.com_0.localstorage
. The File System Events API can't see the file contents, but it can see the file names! And because Safari names files after the web sites you visit, the File System Events API can be used to determine your web browsing history. Privacy violation! That's just one example I thought of to illustrate how file system events could be used to reveal protected information. There are undoubtedly other ways.
If you look at this vulnerability, as well as the Automator workflow vulnerability that I found back when Mojave was released, these aren't complicated privacy protection bypasses. They just require a certain breadth of knowledge about Mac development. Is that lacking now in Cupertino? I don't know the answer to this question, but clearly there are serious engineering failures occurring that Apple needs to explain and correct.
I've said this before, and I'll say it again: Don't Panic! Privacy protection is a new feature in macOS 10.14 Mojave and macOS 10.15 Catalina. Any weakness in the privacy protection is simply a flaw in this feature. You're as safe on Catalina as you were on High Sierra, which did not have this feature at all. You just might not be safer on Catalina than you were on High Sierra. The only danger here that's new is in your own mind: overconfidence in macOS privacy protections. Don't you feel better now for clicking all those permission dialogs?
As I mentioned in my blog post yesterday, I've also found two additional macOS vulnerabilities that I haven't yet reported to Apple. In my opinion, those two are more severe than the one I describe here. I'm not going to report the vulnerabilities until Apple opens the Mac bug bounty program, so if you want me to report the bugs ASAP, let Apple know you want them to get moving.