Safari runs disabled extensions

January 26 2020 by Jeff Johnson

Little Snitch is great at catching apps "phoning home". Much to my surprise, a couple of months ago Little Snitch caught a disabled Safari extension phoning home (where "home" was Amazon Web Services). In fact this extension had never been enabled in Safari. After further investigation I learned that on every launch, Safari runs every registered extension — that is, every extension that appears in Safari's Extensions Preferences — whether the extension is enabled or disabled.

Safari Extensions Preferences

To be clear, Safari does not load a disabled extension's JavaScript into web pages. A modern "Safari app extension" has several parts, including the following:

  1. An app, distributed as an .app bundle. The app contains native Mac executable code inside the Contents/MacOS folder of its bundle.
  2. An app extension, distributed as an .appex bundle inside the Contents/PlugIns folder of the .app bundle. The app extension also contains native Mac executable code in the Contents/MacOS folder of its bundle.
  3. JavaScript and CSS, distributed as .js and .css files inside the Contents/Resources folder of the .appex bundle.

On every launch, Safari runs 2, the native Mac executable code of the .appex bundle, regardless of whether the extension is enabled in Safari's Extensions Preferences. Safari does not load 3, the JavaScript and CSS, unless the extension is enabled.

Every app extension must be sandboxed, otherwise Safari refuses to register the extension, and sandboxing strictly limits the capabilities of app extensions. However, an app extension can still have network entitlements, which would allow the extension to connect to the internet and phone home. My own Safari app extension StopTheMadness does not have network entitlements, as you can verify using this Terminal command:

codesign --display --entitlements - /Applications/

StopTheMadness cannot phone home, and this is by my design, to protect your privacy. Nonetheless, some app extensions do have network entitlements, including some app extensions in the Mac App Store. Thus, those extensions have the capability of phoning home. Moreover, when you install a Safari app extension from the Mac App Store, the extension is automatically registered in Safari. As a consequence, all you have to do is install a Safari app extension from the Mac App Store, and Safari will run the native Mac executable code inside the app extension, even if you never launch the extension's app, and even if you never enable the extension in Safari's Preferences.

I reported this issue to Apple Product Security on November 17 2019. I received a reply from Apple Product Security on December 16 that said they do not see any actual security implications from my report. I replied, arguing that it was a privacy violation. A disabled extension can phone home without the consent of the user, indeed without the knowledge of the user, and expose information about the user: the user's IP address, the user's username (which is probably their real name), the fact that the user has installed the extension, the exact time that the user launches Safari, every time the user launches Safari, etc. I also suggested to Apple Product Security that executing native Mac code without any action by the user is a security problem, and furthermore that a maliciously crafted app extension could exploit any vulnerabilities in the SafariServices API that may exist, or exploit any sandbox escapes that may exist, despite being disabled in Safari, and again without any action at all by the user, except for installing the app. I received another reply from Apple Product Security on January 24 2020 reiterating that they do not see any actual security implications. Hence, I'm disclosing the issue now, and I'll let the public decide whether there are security implications. Maybe you'll agree with Apple Product Security, or maybe you won't, but in any case I've done all I can to try to responsibly notify the vendor of the issue. I do find the vendor's attitude strange in this case, the same vendor who claims "Privacy is a fundamental human right. At Apple, it’s also one of our core values."

If you want to see this issue in action, I'm providing a sample Safari app extension and the source code for the sample app for download. These are the same files that I provided to Apple Product Security. As you can see in the Xcode project, the Safari app extension simply logs "SafariExtensionHandler init" to the Console when it runs:

-(instancetype)init {
	NSLog(@"SafariExtensionHandler init");
	self = [super init];
	return self;

To reproduce:

  1. Download
  2. Quit Safari.
  3. Unzip, launch, and then quit the ExtensionTest app. You need to run the app once in order to register the bundled Safari extension. That step is necessary for apps distributed outside the Mac App Store. (As I mentioned earlier, the Mac App Store automatically registers installed Safari extensions.)
  4. Launch the Console app and enter "SafariExtensionHandler" in its search field. Console must be launched first, before launching Safari (because Console is the worst nowadays).
  5. Launch Safari.

You should then see "SafariExtensionHandler init" logged in Console, even though you never enabled the extension in Safari. Of course, logging was just for demonstration purposes; at that point, an app extension could do whatever it wants.

It's also worth noting that if you install a Safari app extension, enable it in Safari's Extensions Preferences, but then at some later date decide to disable the Safari extension, Safari will still run the app extension on launch, unless you delete the extension's app. Merely disabling the extension is not enough to stop Safari from running it. Once an extension is registered with Safari, the app extension will get run whenever Safari launches. Removing the extension from your disk is the only way to stop that.

Jeff Johnson (My apps, PayPal.Me)