Last Week on My Mac: Enter the codeless TemplateApp

It was inevitable that, after we got dataless files, we should also have codeless apps. Now they have arrived in Sonoma, in the form of Web Apps, as I described last week. The idea of a codeless or ‘low-code’ app is old, and there are already plenty of examples available on macOS and other operating systems, but as far as I’m aware, this is the first time for macOS itself, at least in the current threat landscape.

Web Apps are really quite simple beasts: all they provide is a property list defining the app’s scope in terms of its domain URL, its Home page within that, and an icon to use. LaunchServices registers them against a UUID, applies an ad hoc signature, and keeps a record of the app bundle’s cdhashes from that signature, against which to validate its contents before trying to run it in the future.

Knowing that this is a TemplateApp, when it comes to run it, LaunchServices substitutes the executable code from the Web App supplied in a Cryptex. Options are passed to the Web App code, effectively running it as the command
[…]/Web App.app/Contents/MacOS/Web App --bundlepath "[~]/Applications/AppName.app" --sandboxextension “[…];com.apple.app-sandbox.read;[…];[~]/Applications/AppName.app" --bundleidentifier "com.apple.Safari.WebApp.[UUID]"
for the Web App named AppName.app with the assigned UUID.

Despite its reliance on an ad hoc signature, this method is primarily secured by registration of the app’s UUID with LaunchServices. To craft a changed Web App would require it to be re-signed and its new cdhashes registered against that UUID with LaunchServices. Even then, the crafted app remains constrained by the Web App’s executable code secured in its Cryptex.

As you may have noticed, this method has one obvious disadvantage: the Web App will only run in that copy of LaunchServices, on that Mac. Boot the same Mac from another Sonoma installation, or copy the app to a different Mac, and LaunchServices there has no record of a TemplateApp with that UUID, so it refuses, reporting that the app is broken. Maybe in future Apple will provide a convenient way for that installation of macOS to register the Web App against its own assigned UUID, and re-sign it accordingly.

It’s also worth noting that rebuilding the LaunchServices database might render existing Web Apps unlaunchable. This can be performed by some third-party utilities like OnyX or the undocumented command tool lsregister. This is an area that I’ll be exploring in the near future, including whether it’s possible to use that tool to register Web Apps that haven’t been built on that system.

These appear to be the first such TemplateApps in macOS, and they have a promising future. Although you might be unimpressed with such web apps, or frustrated by their URL sandboxing, similar codeless TemplateApps might have greater appeal. For the moment, there’s no other type of TemplateApp supported by an app in the same Cryptex path, /System/Volumes/Preboot/Cryptexes/App/System/Library/CoreServices/, but I suspect that this won’t be Apple’s last.

Many smaller Mac apps consist largely of GUI wrappers for command tools, making them convenient and accessible. An example of my own is Spundle, which calls hdiutil to work with sparse bundles. It wouldn’t be hard to package those with an interface defined in a property list, run them using executable code in another app in a Cryptex, and present them as TemplateApps. That could even extend to a whole scripting language, run by a suitably sandboxed interpreter.

Presenting the TemplateApp’s executable code in a Cryptex not only gives it good security, but it becomes easy to update outside of macOS updates, just as Rapid Security Responses (RSRs) and Safari are now. Securing the app bundle using an ad hoc signature and registered UUID sidesteps all the problems with regular code-signing certificates. I’m looking forward to seeing what else Apple does with TemplateApps in the future.