Library failure under macOS 12.5

It looks like there’s an issue in macOS 12.5 with loading third-party frameworks via apps, as done with Shane's Script Library Pack.app. For now, the only solution is to embed the relevant script libraries within your own apps for deployment.

The script libraries in question are: BridgePlus, SqLite Lib2 and Myriad Tables. You can export them from Shane's Script Library Pack.app by launching it and clicking the More button.

If applets containing the libraries are saved from Intel Macs, they will also need to be code-signed (all Apple Silicon applets are signed already).

Apologies for any convenience. It’s all beyond my control, alas.

Hi Shane,

If I understand you correctly, what you’re saying is that as of 12.5 a codesigned app will not load (unsigned) libraries from /Library/Script Libraries and ~/Library/Script Libraries. Is that right?

If so, I would not categorize that as a “failure” (which implies a macOS bug, to be reported and fixed) but as an intentional change in macOS’s security policy, part of Apple’s general movement toward requiring all executable code is codesigned.

FWIW, I quickly skimmed the 12.5 security notes and didn’t see anything specifically about codesigning and AS libraries, but it does sound like an intentional tightening of security policy around scripting and automation in general, which is both needed and overdue. (Sad to say, but the only real growth industry for AppleScript &co these days is the malware market.) If you know of any official Apple docs mentioning it, please do share.

An “all libraries must be signed” policy [1] makes a lot of sense in light of recurrent supply-chain attacks, where malware authors insert malicious code, not into the apps themselves, but into the 3rd-party libraries used by those apps (and in the libraries used by those libraries, and so on).

Supply-chain attacks are not a new phenomenon. It’s just that the programmer world is taking its sweet time to start addressing it, because it’s a monster they created and they know it will take a lot of hard work to fix now.

So it’s good if Apple is now forcing the issue by requiring all code be signed before it can freely run on anyone’s machines but its authors’.

In essence, a code signature is a binding declaration by that software’s author: “I personally wrote this software, and I take responsibility for everything that it does.” To use a comparison: there’s a good reason why airport customs always asks if you packed your own suitcases, or if someone else packed them for you. Knowing provenance is critical.

Codesigning itself does not guarantee that the code is safe and free of malware (although related processes such as notarization can include checks for some recognized naughties), as a malware author can always sign his own code. But it does:

  1. Guarantee that if signed code is later on tampered with, that tampering is detected; and

  2. Enable software distributors (in this case Apple) to blacklist any program immediately on it being reported to contain malware; and to provisionally suspend or permanently revoke the credentials of any developer found to be accidentally/deliberately malware so that all their other code is immediately blocked from running too.

Tying the code to its authors is a step to making those authors answerable for their code’s [mis]behavior. As I say, retrofitting it now is going to be painful. But it does right by the Users, a nice change from the traditional developer “I’m not responsible” policy.

[1] Mind, it’d have been infinitely less painful and messy had all this user-level security had been built-in from Day One of Personal Computing, instead of it now being retrofitted to free-for-all chaos several decades after. But that’s the historical realities of business economics, 90s processing power, and the 80s not having a crystal ball. It is what it is, and we just have to pay the bill now.

No. I’m talking about a script library within a (in this case notarized) app’s /Contents/Libraries/Script Libraries directory. See:

Specifically:

Script libraries may now be located in any installed application bundle, in the Contents/Library/Script Libraries directory of the bundle. This allows distributing libraries that are associated with an application, or creating applications that exist solely to distribute libraries.

The issues with putting them in a standard library folder are (a) you can’t notarize a .scptd file, and (b) there’s no mechanism available in the OS for a user to approve the loading of other than apps.

Sorry, I’m still confused. The above sentence makes it sound as if embedding a 3rd-party library in your app’s bundle is now busted, meaning e.g. this would no longer work:

MyApp.app/Contents/Libraries/Script Libraries/3rdPartyLib.scptd 

But I don’t think that’s what you mean. (And it would be a serious bug if it was.)

I did see the word “framework” in your original post. Are you saying that a codesigned app can still load some (unsigned) AS libraries from /Library/Script Libraries and ~/Library/Script Libraries, but not if those libraries themselves use 3rd-party ObjC frameworks?

This would make sense as macOS is pretty strict nowadays w.r.t. apps that run Swift/ObjC/C++/etc code, requiring all of that code to be codesigned by the app’s author in order to run it, regardless of where it comes from. e.g. If your sqlite AppleScript library keeps its own copy of libsqlite in its .scptd bundle, if an AppleScripter wants to use your library in their codesigned AS app they must embed, and thus re-sign, your library and the libsqlite code contained within it, or else their app will no longer load it.

Is that correct? Thanks.

No. The key sentence you’re missing is applications that exist solely to distribute libraries. Save me some typing and go here:

and download Shane's Script Library Pack.app.

OK. Thid was not at all obvious in your previous posts, which talked about “library failures” and “third-party frameworks”.

So you’re talking about an AS library which is embedded in an (otherwise non-functional) app for distribution purposes, as per #8 here. The user downloads that app and installs it on their machine, and AS can now find and use all the libraries embedded within it.

And you’re saying 12.5 no longer allows AppleScripts to import libraries from this installed “library wrapper” app?

Good. I trust that’s an intentional, permanent change by Apple.

This was always a serious misfeature, and a genuine security hole too. It made it easy to smuggle a malicious AppleScript library onto AppleScript’s default search path by tucking it inside an otherwise innocuous app, e.g.:

/Applications/SomeApp.app/Contents/Library/Script Libraries/Text.scpt

would make a library named “Text” visible to all AppleScripts installed on that Mac.

Furthermore, since it’s a native AS library, it executes inside your script’s context (e.g. Script Debugger, FastScripts, ASOC app, or AS applet), thereby escaping the original app’s own sandbox. Yipe!

ISTR (vaguely) voicing my own concern to one of the Chrises at the time. I think originally it was higher in the search hierarchy so app-installed libraries could even mask libraries installed in /Library/Script Libraries and so get loaded first. The final implementation puts app-embedded libraries last on AS search path, which ameliorates that risk—although that still leaves two exploitable holes:

  1. If the user doesn’t already have the real “Text” library installed on their Mac, use script "Text" would end up importing and using the malicious version; and

  2. If two differently-named library-wrapper apps are installed on the same Mac, one containing the legitimate “Text” library and the other with a malicious “Text” library, which of those libraries get be loaded by use script "Text"? It could be either, presumably depending on which app bundle AS searches first.

The only reason that this was never a practical attack vector with known exploits out in the wild is because the number of Mac users who run AppleScripts is tiny, and the number of those users who use third-party libraries miniscule. So any blackhat who’d waste their time making it would have to be extraordinarily bored.

Still, the idea that a globally-importable library could be inserted onto a user’s machine without the user knowingly, intentionally installing it is frightening. In hindsight I should’ve called it out as a Completely Bad Idea and pressed against it being implemented at all, e.g. by filing a Radar report to make Apple’s security team aware of the hole being opened. But I didn’t understand security so well a decade ago.

I’ve spent more time around NPM et al since then, so am more aware now. Still not an expert, but I know enough about the issues to know those big popular languages (Node.js, Python, etc) and their enormous library repositories are a fricking security horror, which 99% of those language users deal with by completely ignoring/being completely ignorant of/denying there is even a problem. (And internet commerce runs on those langs! Our PII and CC numbers, in their hands!)

Addendum: App-embedded AS libraries could have been acceptable, had AS required the library’s location to be explicitly declared in the tell/use statement, e.g.:

use script "Myriad Tables Lib" of application "Shane’s Script Library Pack.app"

Obviously with that there is still the issue of having two different apps of that name on the same Mac, but that’s no different to the issue AppleScripters already have when targeting scriptable apps by name/bundle ID, and there is multiple identically-named/IDd versions of the same app installed (Hello, Adobe Illustrator.app). But at least the code now makes explicit where that library is to be found, making unintentional imports from anywhere else impossible.

Anyway, it would not surprise me if your SLP is the only app on earth to distribute+install AS libraries this way. So it sounds like the right solution is for you to go back to distributing thoaw libraries as simple .scptd files, which AppleScript users can install into their Script Libraries folder the old-fashioned way. (And they can deal with the inevitable pains of codesigning, distributing, etc their own software from there; but that’s a separate problem.)

Or, if you really must have them as .app bundles, you could go really old school and convert them into “Script Servers” (remember those?!): stay-open AS applets that expose their handlers for other scripts to call via Apple events, just like any other scriptable faceless background app.

Thank you for clarifying your original post. (And for the fun trip down the old memory path.:slight_smile:

Now we just need Apple to clarify its policies, which studiously remain clear as mud. We live in hope.