Gatekeeper does not lift the quarantine attribute of a signed and notarized downloaded application

I distribute an application in a zip file from my website. the application needs access to some files next to it to run properly. The application is correctly signed and notarized and stapled.Of course if I download it from my website, it gets the quarantine attribute. When I try to open it for the first time, a gatekeeper warning saying that the application comes from the internet, but has been checked by apple and no malware has been detected is displayed. My impression is that the application has been correctly signed and notarized. but If confirm that I wan to open it, the quarantine attribute is not deleted.

spctl -a -v /path/to/Myapp.app
path/to/Myapp.app: accepted
source=Notarized Developer ID

Replies

the application needs access to some files next to it to run properly.

That sounds like you’re running afoul of app translocation. App translocation and quarantine are different things, albeit related. For more background on the former, see App Translocation Notes.

If confirm that I wan to open it, the quarantine attribute is not deleted.

Right. Quoting that post:

The exact circumstances where the system translocates an app is not documented and has changed over time.

I believe that the current situation is that we only remove app translocation if the user moves the app using the Finder. However, this isn’t something I track in depth because, as I wrote it that post, it’s not something we officially document.

That post also says:

It’s best to structure your app so that it works regardless of whether it’s translocated or not.

which is the real issue here. Why does your app depend on accessing files relative to the app on disk? Doing that is an obvious security concern — because those files are not sealed over by your code signature — and that’s why app translocation makes it hard.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This is indeed a translocation problem. My app is an audio app that need to access some Impulse Response wav files to create reverberation. I have a preset folder next to it where the users can put their own wav file to have it available in the app and create their own reverbs. that is why I need this folder. Also the app should be able to copy paste some files in its own folder, like the license file.

What I don't understand is exactly what is not documented on Translocation. what is also weird is that for the previous versions, it worked perfectly. Is there a way to scan what triggers this translocation ?

For those following along at home, I’ll be helping arbanedev in a different context.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo Thank you for your help, the threads you mentioned were very helpful

I finally managed to distribute it cleanly by packaging the application in a dmg. It also eased the notarization and stapling process. As I'm developing the app with Max/MSP (a graphical real time audio framework allowing to package audio application), I was forced to keep the same architecture as I don't have access to all convenient functions and method for the file management of the app. It seems that using a dmg and forcing the user to drag the app in the application folder disables the translocation.

Here are some resources that also helped me to understand translocation : https://eclecticlight.co/2022/09/06/dont-run-that-app-where-it-landed-how-translocation-can-cause-crashes/ https://eclecticlight.co/2023/05/09/what-causes-app-translocation/

@eskimo

I'm having the exact same problem although our app is distributed through a DMG. The app is signed and notarized and spctl as well as codesign verify doesn't show any problems.

However, when it is launched some users (it's apparently not happening for all) get the "app cannot be opened because the developer cannot be verified". xattr shows that the quarantine attribute is set and not cleared:

/Applications % xattr -l MyApp.app
com.apple.macl: 
com.apple.provenance: 
com.apple.quarantine: 0183;66100fe4;Safari;76643850-7086-4346-8B1E-02EF43C9799D

What can I do to fix this?

Just in case this is relevant (it may be following the rest of the conversation here): Our app has a bundled Python runtime which - when the app is started - will create compiled files which would invalidate the bundle's signature. Hence, we're copying the relevant Python files to a subfolder within Application Support and our app's bundled Cython will then read/write files in this location. However, this shouldn't be any different to reading/writing user preference or similar files in this location which is what we've been doing forever without these kind of issues.

I would appreciate any ideas on how to get around this or what else to try to troubleshoot this further.

Thank you!

However, when it is launched some users (it's apparently not happening for all)

I think that’s key. My general advice on this front is to test your app using the process described in Testing a Notarised Product. If things work in a clean VM, you know that your app is probably OK, and that problems being seen by specific users are related to their machine setup.

So, does your app pass this test?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ok, thanks for that. I set up a clean Sonoma 14.4.1 VM, downloaded the DMG from our local build server, installed it and I'm getting the "app can't be opened because the developer cannot be verified" I verified both the app and the DMG using the commands from the Testing a Notarized Product link you provided.

spctl -a -t exec -vvv /Applications/MyApp.app
/Applications/MyApp.app: accepted
source=Notarized Developer ID
origin=Developer ID Application: ***
spctl -a -t open -vvv --context context:primary-signature ~/Downloads/MyApp.dmg
/Users/flo/Downloads/MyApp.dmg: accepted
source=Notarized Developer ID
origin=Developer ID Application: ***

I found one of your other posts where you wrote about the new syspolicy_check. I tried that and I am indeed getting an error:

syspolicy_check distribution MyApp.app 
App has failed one or more pre-distribution checks.
---------------------------------------------------------------
Bad Load Command
    File: MyApp.app/Contents/MacOS/../Frameworks/libavcodec.dylib 
    Severity: Fatal 
    Full Error: /Users/flo/Downloads/MyApp.app/Contents/MacOS/../Frameworks/libavcodec.dylib attempts to 
        load 
        /Users/flo/.conan/data/openssl/3.1.3/_/_/package/869f360e5d846618772ce5abc649684a86565498/lib/libswresample.dylib. 
        Resolved load path: (path not found) 
    Type: Notary Error 

---------------------------------------------------------------

This is a very odd one. The path mentioned is indeed not present on the machine I'm running the app on. But when I run otool, I don't see this path.

otool -L /Users/flo/Downloads/MyApp.app/Contents/Frameworks/libavcodec.dylib 

/Users/flo/Downloads/MyApp.app/Contents/Frameworks/libavcodec.dylib (architecture x86_64):
	@rpath/libavcodec.dylib (compatibility version 59.0.0, current version 59.37.100)
	@rpath/libswresample.dylib (compatibility version 4.0.0, current version 4.7.100)
	@rpath/libavutil.dylib (compatibility version 57.0.0, current version 57.28.100)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox (compatibility version 1.0.0, current version 1000.0.0)
	@rpath/libz.dylib (compatibility version 1.0.0, current version 1.3.0)
	/System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1677.104.0)
	/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1069.24.0)
/Users/flo/Downloads/MyApp.app/Contents/Frameworks/libavcodec.dylib (architecture arm64):
	@rpath/libavcodec.dylib (compatibility version 59.0.0, current version 59.37.100)
	@rpath/libswresample.dylib (compatibility version 4.0.0, current version 4.7.100)
	@rpath/libavutil.dylib (compatibility version 57.0.0, current version 57.28.100)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1500.65.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox (compatibility version 1.0.0, current version 1000.0.0)
	@rpath/libz.dylib (compatibility version 1.0.0, current version 1.3.0)
	/System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1971.0.0)
	/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1228.0.0)

Can you help me understand the issue better? Thank you very much!

This is a very odd one.

Au contraire, this one of the most common Gatekeeper issues I see today. See Resolving Gatekeeper Problems Caused by Dangling Load Command Paths.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you so much! I haven't touched that entitlements file in quite a while. Wasn't aware the com.apple.security.cs.disable-library-validation was still in there. It didn't do any harm with the previous version of the libraries where we used a different approach to build them. I removed it and now Gatekeeper is happy! Success!!

For my understanding: the library libavcodec.dylib tries to load this dangling library: /Users/flo/.conan/data/openssl/3.1.3/_/_/package/869f360e5d846618772ce5abc649684a86565498/lib/libswresample.dylib

Why is that not shown in the otool -L output? That output does indeed reference libswresample, but with a different path: @rpath/libswresample.dylib There is also no error in operation.

In contrast, otool -l prints the load commands, how is that different from the output of otool -L?

I'm trying to understand how I could possibly catch this since it doesn't cause a linker error.

Thanks!

Why is that not shown in the otool -L output?

That command is showing an rpath-relative reference, which the dynamic linker tries to resolve using all the rpaths. Those are configured by LC_RPATH commands, which aren’t shown in otool -L. Worse yet, the rpath commands might not be in this library. The dynamic linker builds of stack of rpath entries from the libraries that loaded this library.

In contrast, otool -l prints the load commands, how is that different from the output of otool -L?

They are completely different things. -l prints all the load commands. -L prints just the install names from the LC_LOAD_DYLIB load commands.

I talk about this extensively in Dynamic Library Identification.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey again!

Looks like I spoke too soon. Setting the disable library validation entitlement to false made Gatekeeper happy but introduced a new much bigger problem.

Our app supports using external, professional video hardware by Blackmagic and AJA. For AJA, we're shipping the required libraries as part of the app bundle so I guess that's why it still works.

However, for Blackmagic devices, the app is just built against a small SDK. The SDK will load the actual framework from a system folder (/Library/Frameworks/DeckLinkAPI.framework/Versions/A/DeckLinkAPI). This works when building with Xcode and signing the app locally.

But when running the release build, the Blackmagic devices are not loaded at all. Is that because the library validation doesn't allow libraries to be accessed which are outside the bundle? With disable library validation turned on this worked but we got the other Gatekeeper issue as described above.

Is there a way forward?

Thanks so much!

Is there

Nevermind, I removed the dangling RPATHs from the relevant libs using install_name_tool and turned off library validation and now it's working.

Our app bundle itself defines the run path search paths. I guess our build system for the 3rd party libraries (Conan) sets those in order to build the libraries with dependencies but I'm not sure.

Anyway, solved now. Thanks!

Yeah, if you load plug-ins from third parties then you really do need to disable library validation, and so the only option is to fix any dangling load commands.

FYI, starting with macOS 14 you can apply custom library validation constraints, allowing you to load plug-ins from specific vendors. See WWDC 2023 Session 10266 Protect your Mac app with environment constraints and Applying launch environment and library constraints for more.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"