I am developing an Authorisation Plugin which talks to Launch daemons over XPC.
Above is working neat, now I have to decide on how to get it installed on a machine.
Installation requires.
Plugin Installation
Launch Daemon Installation
Both require
Moving binary and text (.plist) file into privileged system managed directory.
Firing install/load commands as root (sudo).
I have referred this post BSD Privilege Escalation on macOS, but I am still not clear how to approach this.
Q: My requirement is:
I can use .pkg builder and install via script, however I have some initialisation task that needs to be performed. User will enter some details talk to a remote server and get some keys, all goes well restarts the system and my authorisation plugin will welcome him and get him started.
If I cannot perform initialisation I will have to do it post restart on login screen which I want to avoid if possible.
I tried unconventional way of using AppleScript from a SwiftUI application to run privileged commands, I am fine if it prompts for admin credentials, but it did not work.
I don't want that I do something and when approving it from Apple it gets rejected.
Basically, how can I provide some GUI to do initialisation during installation or may be an app which helps in this.
Q: Please also guide if I am doing elevated actions, how will it affect app distribution mechanism. In Read Me for EvenBetterAuthorizationSample I read it does.
Thanks.
Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi,
when creating a CryptoTokenKit extension according to https://developer.apple.com/documentation/cryptotokenkit/authenticating-users-with-a-cryptographic-token, it is neccessary to register it under the securityagent in order to make the CTK usable before login. i.e. we want to run
sudo -u _securityagent /Applications/HostApp.app/Contents/MacOS/HostApp
However, even with the empty application the command fails with
illegal hardware instruction sudo -u _securityagent /Applications/HostApp.app/Contents/MacOS/HostApp
I see that it always crashes when the HostApp is sandboxed, but it does not work even without sandboxing (i am sharing the error report message below).
i actually noticed that when the HostApp is sandboxed and I run the above command, the extension starts to be usable even before login, even though i see the HostApp crash. The same does not happen without the sandbox
So I am curious how to in fact properly register the CTK extension under security agent? Also am not sure how to unregister it from the _securityagent
thank you for your help
Version: 1.0 (1)
Code Type: X86-64 (Native)
Parent Process: Exited process [9395]
Responsible: Terminal [399]
User ID: 92
Date/Time: 2025-03-21 18:54:03.0684 +0100
OS Version: macOS 15.3.2 (24D81)
Report Version: 12
Bridge OS Version: 9.3 (22P3060)
Anonymous UUID: 41F9918C-5BCA-01C7-59C2-3E8CFC3F8653
Sleep/Wake UUID: 8AB66C75-3C32-41D4-9BD4-887B0FB468FE
Time Awake Since Boot: 4300 seconds
Time Since Wake: 1369 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: WMClientWindowManager
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [9396]
Application Specific Signatures:
API Misuse
Thread 0 Crashed:: Dispatch queue: WMClientWindowManager
0 libxpc.dylib 0x7ff80667b2bd _xpc_api_misuse + 113
1 libxpc.dylib 0x7ff80665f0e4 xpc_connection_set_target_uid + 187
2 WindowManagement 0x7ffd0b946693 -[WMClientWindowManager _createXPCConnection] + 1011
3 WindowManagement 0x7ffd0b947361 -[WMClientWindowManager _xpcConnection] + 65
4 WindowManagement 0x7ffd0b9447c9 __31-[WMClientWindowManager stages]_block_invoke + 41
5 libdispatch.dylib 0x7ff8067af7e2 _dispatch_client_callout + 8
6 libdispatch.dylib 0x7ff8067bca2c _dispatch_lane_barrier_sync_invoke_and_complete + 60
7 WindowManagement 0x7ffd0b9446fc -[WMClientWindowManager stages] + 268
8 AppKit 0x7ff80b1fd0b7 __54-[NSWMWindowCoordinator initializeStageFramesIfNeeded]_block_invoke + 30
9 libdispatch.dylib 0x7ff8067af7e2 _dispatch_client_callout + 8
10 libdispatch.dylib 0x7ff8067b0aa2 _dispatch_once_callout + 20
11 AppKit 0x7ff80b1fd060 -[NSWMWindowCoordinator initializeStageFramesIfNeeded] + 296
12 AppKit 0x7ff80a3b3701 -[NSWindow _commonInitFrame:styleMask:backing:defer:] + 888
13 AppKit 0x7ff80a3b2f77 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1222
14 AppKit 0x7ff80a3b2aa9 -[NSWindow initWithContentRect:styleMask:backing:defer:] + 42
15 SwiftUI 0x7ff917f321e0 0x7ff91776f000 + 8139232
16 SwiftUI 0x7ff917a8e2f2 0x7ff91776f000 + 3273458
17 SwiftUI 0x7ff917bccfba 0x7ff91776f000 + 4579258
18 SwiftUI 0x7ff917f2ca8e 0x7ff91776f000 + 8116878
19 SwiftUI 0x7ff917f24a65 0x7ff91776f000 + 8084069
20 SwiftUI 0x7ff917f21540 0x7ff91776f000 + 8070464
21 SwiftUI 0x7ff91849e9f1 0x7ff91776f000 + 13826545
22 SwiftUICore 0x7ffb13103ea5 0x7ffb12c81000 + 4730533
23 SwiftUICore 0x7ffb13102e0f 0x7ffb12c81000 + 4726287
24 SwiftUI 0x7ff91849e903 0x7ff91776f000 + 13826307
25 SwiftUI 0x7ff91849bc1c 0x7ff91776f000 + 13814812
26 AppKit 0x7ff80a54f191 -[NSApplication _doOpenUntitled] + 422
27 AppKit 0x7ff80a4efc59 __58-[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:]_block_invoke + 237
28 AppKit 0x7ff80a963818 __102-[NSApplication _reopenWindowsAsNecessaryIncludingRestorableState:withFullFidelity:completionHandler:]_block_invoke + 101
29 AppKit 0x7ff80a4ef6fa __97-[NSDocumentController(NSInternal) _autoreopenDocumentsIgnoringExpendable:withCompletionHandler:]_block_invoke_3 + 148
30 AppKit 0x7ff80a4eee8f -[NSDocumentController(NSInternal) _autoreopenDocumentsIgnoringExpendable:withCompletionHandler:] + 635
31 AppKit 0x7ff80a96373d -[NSApplication _reopenWindowsAsNecessaryIncludingRestorableState:withFullFidelity:completionHandler:] + 269
32 AppKit 0x7ff80a3a6259 -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 529
33 AppKit 0x7ff80a3a5eb9 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 679
34 Foundation 0x7ff807a4b471 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 307
35 Foundation 0x7ff807a4b285 _NSAppleEventManagerGenericHandler + 80
36 AE 0x7ff80e0e4e95 0x7ff80e0da000 + 44693
37 AE 0x7ff80e0e4723 0x7ff80e0da000 + 42787
38 AE 0x7ff80e0de028 aeProcessAppleEvent + 409
39 HIToolbox 0x7ff81217b836 AEProcessAppleEvent + 55
40 AppKit 0x7ff80a39ee6a _DPSNextEvent + 1725
41 AppKit 0x7ff80adf38b8 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1290
42 AppKit 0x7ff80a38faa9 -[NSApplication run] + 610
43 AppKit 0x7ff80a362d34 NSApplicationMain + 823
44 SwiftUI 0x7ff9177a7da1 0x7ff91776f000 + 232865
45 SwiftUI 0x7ff917af0d40 0x7ff91776f000 + 3677504
46 SwiftUI 0x7ff917d8fef8 0x7ff91776f000 + 6426360
47 Crescendo CryptoTokenKit 0x10b1baf6e static HostApp.$main() + 30
48 Crescendo CryptoTokenKit 0x10b1bd2f9 main + 9 (HostApp.swift:24)
49 dyld 0x7ff8065c82cd start + 1805
Hi everyone,
I’ve been working on storing keys and passwords in the macOS Keychain using the Keychain Services API. Specifically, I’m leveraging SecAccessControlCreateWithFlags to bind items to access control flags, and overall, it’s been working smoothly.
I have a question regarding the .applicationPassword flag of SecAccessControlCreateWithFlags. While it successfully prompts the user to input a password, there are no apparent password rules, even a simple “1” is accepted.
My questions are:
Is there a way to enforce strong password requirements when using the .applicationPassword flag?
If enforcing strong passwords isn’t possible, is there an alternative approach to provide a predefined strong password during the creation process, bypassing the need for user input?
With SecAccessControlCreateWithFlags, I noticed the item isn’t stored in the traditional file-based Keychain but in an iOS-style Keychain, is there a way to store it in a file-based Keychain while marking it as unexportable?
I appreciate any insights or suggestions.
Thank you!
Neil
Our app uses Face ID to optionally secure access to the app for device owner. This not the new 'Require Face ID' feature of iOS 18 - this is our own custom implementation that has some other related logic for authentication handling.
Starting in iOS 18.3.1, starting the app results in multiple Face Id checks being fired - sometimes just a couple but sometimes many more.
Curiously, this is happening even when I completely disable any code we have that prompts for Face ID. It appears to come from nowhere.
This does not happen on prior iOS 18 releases so, while I might be doing something improper in the code, something specific has changed in iOS 18.3.1 to cause this issue to manifest.
I'm looking for advice as to what could be occurring here, how to debug a Face Id check that appears to come from nowhere, and what, if any, workarounds exist.
I'm building a tool for admins in the enterprise context. The app needs to do some things as root, such as executing a script.
I was hoping to implement a workflow where the user clicks a button, then will be shown the authentication prompt, enter the credentials and then execute the desired action. However, I couldn't find a way to implement this. AuthorizationExecuteWithPrivileges looked promising, but that's deprecated since 10.7.
I've now tried to use a launch daemon that's contained in the app bundle with XPC, but that seems overly complicated and has several downsides (daemon with global machservice and the approval of a launch daemon suggests to the user that something's always running in the background). Also I'd like to stream the output of the executed scripts in real time back to the UI which seems very complicated to implement in this fashion.
Is there a better way to enable an app to perform authorized privilege escalation for certain actions? What about privileged helper tools? I couldn't find any documentation about them. I know privilege escalation is not allowed in the App Store, but that's not relevant for us.
Problem Description:
In our App, When we launch the web login part using ASWebAuthentication + Universal Links with callback scheme as "https", we are not receiving callback.
Note:
We are using "SwiftUIWebAuthentication" Swift Package Manager to display page in ASWebAuth.
But when we use custom url scheme instead of Universal link, app able to receive call back every time.
We use ".onOpenURL" to receive universal link callback scheme.
I'm trying to export and re-import a P-256 private key that was originally generated via SecKeyCreateRandomKey(), but I keep running into roadblocks. The key is simply exported via SecItemExport() with format formatWrappedPKCS8, and I did set a password just to be sure.
Do note that I must use the file-based keychain, as the data protection keychain requires a restricted entitlement and I'm not going to pay a yearly fee just to securely store some private keys for a personal project. The 7-day limit for unsigned/self-signed binaries isn't feasible either.
Here's pretty much everything I could think of trying:
Simply using SecItemImport() does import the key, but I cannot set kSecAttrLabel and more importantly: kSecAttrApplicationTag. There just isn't any way to pass these attributes upfront, so it's always imported as Imported Private Key with an empty comment. Keys don't support many attributes to begin with and I need something that's unique to my program but shared across all the relevant key entries, otherwise it's impossible to query for only my program's keys. kSecAttrLabel is already used for something else and is always unique, which really only leaves kSecAttrApplicationTag. I've already accepted that this can be changed via Keychain Access, as this attribute should end up as the entry's comment. At least, that's how it works with SecKeyCreateRandomKey() and SecItemCopyMatching(). I'm trying to get that same behaviour for imports.
Running SecItemUpdate() afterwards to set these 2 attributes doesn't work either, as now the kSecAttrApplicationTag is suddenly used for the entry's label instead of the comment. Even setting kSecAttrComment (just to be certain) doesn't change the comment. I think kSecAttrApplicationTag might be a creation-time attribute only, and since SecItemImport() already created a SecKey I will never be able to set this. It likely falls back to updating the label because it needs to target something that is still mutable?
Using SecItemImport() with a nil keychain (i.e. create a transient key), then persisting that with SecItemAdd() via kSecValueRef does allow me to set the 2 attributes, but now the ACL is lost. Or more precise: the ACL does seem to exist as any OS prompts do show the label I originally set for the ACL, but in Keychain Access it shows as Allow all applications to access this item. I'm looking to enable Confirm before allowing access and add my own program to the Always allow access by these applications list. Private keys outright being open to all programs is of course not acceptable, and I can indeed access them from other programs without any prompts.
Changing the ACL via SecKeychainItemSetAccess() after SecItemAdd() doesn't seem to do anything. It apparently succeeds but nothing changes. I also reopened Keychain Access to make sure it's not a UI "caching" issue.
Creating a transient key first, then getting the raw key via SecKeyCopyExternalRepresentation() and passing that to SecItemAdd() via kSecValueData results in The specified attribute does not exist. This error only disappears if I remove almost all of the attributes. I can pass only kSecValueData, kSecClass and kSecAttrApplicationTag, but then I get The specified item already exists in the keychain errors. I found a doc that explains what determines uniqueness, so here are the rest of the attributes I'm using for SecItemAdd():
kSecClass: not mentioned as part of the primary key but still required, otherwise you'll get One or more parameters passed to a function were not valid.
kSecAttrLabel: needed for my use case and not part of the primary key either, but as I said this results in The specified attribute does not exist.
kSecAttrApplicationLabel: The specified attribute does not exist. As I understand it this should be the SHA1 hash of the public key, passed as Data. Just omitting it would certainly be an option if the other attributes actually worked, but right now I'm passing it to try and construct a truly unique primary key.
kSecAttrApplicationTag: The specified item already exists in the keychain.
kSecAttrKeySizeInBits: The specified attribute does not exist.
kSecAttrEffectiveKeySize: The specified attribute does not exist.
kSecAttrKeyClass: The specified attribute does not exist.
kSecAttrKeyType: The specified attribute does not exist.
It looks like only kSecAttrApplicationTag is accepted, but still ignored for the primary key. Even entering something that is guaranteed to be unique still results in The specified item already exists in the keychain, so I think might actually be targeting literally any key. I decided to create a completely new keychain and import it there (which does succeed), but the key is completely broken. There's no Kind and Usage at the top of Keychain Access and the table view just below it shows symmetric key instead of private. The kSecAttrApplicationTag I'm passing is still being used as the label instead of the comment and there's no ACL. I can't even delete this key because Keychain Access complains that A missing value was detected. It seems like the key doesn't really contain anything unique for its primary key, so it will always match any existing key.
Using SecKeyCreateWithData() and then using that key as the kSecValueRef for SecItemAdd() results in A required entitlement isn't present. I also have to add kSecUseDataProtectionKeychain: false to SecItemAdd() (even though that should already be the default) but then I get The specified item is no longer valid. It may have been deleted from the keychain. This occurs even if I decrypt the PKCS8 manually instead of via SecItemImport(), so it's at least not like it's detecting the transient key somehow. No combination of kSecAttrIsPermanent, kSecUseDataProtectionKeychain and kSecUseKeychain on either SecKeyCreateWithData() or SecItemAdd() changes anything.
I also tried PKCS12 despite that it always expects an "identity" (key + cert), while I only have (and need) a private key. Exporting as formatPKCS12 and importing it with itemTypeAggregate (or itemTypeUnknown) does import the key, and now it's only missing the kSecAttrApplicationTag as the original label is automatically included in the PKCS12. The outItems parameter contains an empty list though, which sort of makes sense because I'm not importing a full "identity". I can at least target the key by kSecAttrLabel for SecItemUpdate(), but any attempt to update the comment once again changes the label so it's not really any better than before.
SecPKCS12Import() doesn't even import anything at all, even though it does return errSecSuccess while also passing kSecImportExportKeychain explicitly.
Is there literally no way?
Hi everyone,
I’d like to clarify something regarding the behavior of Team IDs after an app transfer between Apple Developer accounts.
I have an app update that enforces a force update for all users. My plan is to release this update under the current developer account, and then proceed with transferring the app to a different developer account shortly afterward.
My concern is: once the transfer is complete, will users who download the same app version (released before the transfer) be logged out due to a change in Team ID? Specifically, does the transferred app continue to use the original Team ID (used to sign the last submitted build), or does the Team ID change immediately upon transfer — affecting Keychain access?
Any insights or confirmation on this would be greatly appreciated. Thanks!
Topic:
Privacy & Security
SubTopic:
General
In some crashlog files, there are additional pieces of information related to codesigning.
I can understand what most of themcorresponds to (ID, TeamID, Flags, Validation Category). But there is one I have some doubt about: Trust Level.
As far as I can tell (or at least what Google and other search engines say), this is an unsigned 32 bit integer that defines the trust level with -1 being untrusted, 0, being basically an Apple executable and other potential bigger values corresponding to App Store binaries, Developer ID signature, etc.
Yet, I'm not able to find a corresponding detailed documentation about this on Apple's developer website.
I also had a look at the LightweightCodeRequirements "include" file and there does not seem to be such a field available.
[Q] Is there any official documentation listing the different values for this trust level value and providing a clear description of what it corresponds to?
(Xcode 26.2, iPhone 17 Pro)
I can't seem to get hardware tag checks to work in an app launched without the special "Hardware Memory Tagging" diagnostics. In other words, I have been unable to reproduce the crash example at 6:40 in Apple's video "Secure your app with Memory Integrity Enforcement".
When I write a heap overflow or a UAF, it is picked up perfectly provided I enable the "Hardware Memory Tagging" feature under Scheme Diagnostics.
If I instead add the Enhanced Security capability with the memory-tagging related entitlements:
I'm seeing distinct memory tags being assigned in pointers returned by malloc (without the capability, this is not the case)
Tag mismatches are not being caught or enforced, regardless of soft mode
The behaviour is the same whether I launch from Xcode without "Hardware Memory Tagging", or if I launch the app by tapping it on launchpad. In case it was related to debug builds, I also tried creating an ad hoc IPA and it didn't make any difference.
I realise there's a wrinkle here that the debugger sets MallocTagAll=1, so possibly it will pick up a wider range of issues. However I would have expected that a straight UAF would be caught. For example, this test code demonstrates that tagging is active but it doesn't crash:
#define PTR_TAG(p) ((unsigned)(((uintptr_t)(p) >> 56) & 0xF))
void *p1 = malloc(32);
void *p2 = malloc(32);
void *p3 = malloc(32);
os_log(OS_LOG_DEFAULT, "p1 = %p (tag: %u)\n", p1, PTR_TAG(p1));
os_log(OS_LOG_DEFAULT, "p2 = %p (tag: %u)\n", p2, PTR_TAG(p2));
os_log(OS_LOG_DEFAULT, "p3 = %p (tag: %u)\n", p3, PTR_TAG(p3));
free(p2);
void *p2_realloc = malloc(32);
os_log(OS_LOG_DEFAULT, "p2 after free+malloc = %p (tag: %u)\n", p2_realloc, PTR_TAG(p2_realloc));
// Is p2_realloc the same address as p2 but different tag?
os_log(OS_LOG_DEFAULT, "Same address? %s\n",
((uintptr_t)p2 & 0x00FFFFFFFFFFFFFF) == ((uintptr_t)p2_realloc & 0x00FFFFFFFFFFFFFF)
? "YES" : "NO");
// Now try to use the OLD pointer p2
os_log(OS_LOG_DEFAULT, "Attempting use-after-free via old pointer p2...\n");
volatile char c = *(volatile char *)p2; // Should this crash?
os_log(OS_LOG_DEFAULT, "Read succeeded! Value: %d\n", c);
Example output:
p1 = 0xf00000b71019660 (tag: 15)
p2 = 0x200000b711958c0 (tag: 2)
p3 = 0x300000b711958e0 (tag: 3)
p2 after free+malloc = 0x700000b71019680 (tag: 7)
Same address? NO
Attempting use-after-free via old pointer p2...
Read succeeded! Value: -55
For reference, these are my entitlements.
[Dict]
[Key] application-identifier
[Value]
[String] …
[Key] com.apple.developer.team-identifier
[Value]
[String] …
[Key] com.apple.security.hardened-process
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.checked-allocations
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.checked-allocations.enable-pure-data
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.dyld-ro
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.enhanced-security-version
[Value]
[Int] 1
[Key] com.apple.security.hardened-process.hardened-heap
[Value]
[Bool] true
[Key] com.apple.security.hardened-process.platform-restrictions
[Value]
[Int] 2
[Key] get-task-allow
[Value]
[Bool] true
What do I need to do to make Memory Integrity Enforcement do something outside the debugger?
Hi everyone,
I’m encountering an unexpected Keychain behavior in a production environment and would like to confirm whether this is expected or if I’m missing something.
In my app, I store a deviceId in the Keychain based on the classic KeychainItemWrapper implementation. I extended it by explicitly setting:
kSecAttrAccessible = kSecAttrAccessibleAfterFirstUnlock
My understanding is that kSecAttrAccessibleAfterFirstUnlock should allow Keychain access while the app is running in the background, as long as the device has been unlocked at least once after reboot.
However, after the app went live, I observed that when the app performs background execution (e.g., triggered by background tasks / silent push), Keychain read attempts intermittently fail with:
errSecInteractionNotAllowed (-25308)
This seems inconsistent with the documented behavior of kSecAttrAccessibleAfterFirstUnlock.
Additional context:
The issue never occurs in foreground.
The issue does not appear on development devices.
User devices are not freshly rebooted when this happens.
The Keychain item is created successfully; only background reads fail.
Setting the accessibility to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly produces the same result.
Questions:
Under what circumstances can kSecAttrAccessibleAfterFirstUnlock still cause a -25308 error?
Is there any known restriction when accessing Keychain while the app is running in background execution contexts?
Could certain system states (Low Power Mode, Background App Refresh conditions, device lock state, etc.) cause Keychain reads to be blocked unexpectedly?
Any insights or similar experiences would be greatly appreciated. Thank you!
Issue: Plain Executables Do Not Appear Under “Screen & System Audio Recording” on macOS 26.1 (Tahoe)
Summary
I am investigating a change in macOS 26.1 (Tahoe) where plain (non-bundled) executables that request screen recording access no longer appear under:
System Settings → Privacy & Security → Screen & System Audio Recording
This behavior differs from macOS Sequoia, where these executables did appear in the list and could be managed through the UI. Tahoe still prompts for permission and still allows the executable to capture the screen once permission is granted, but the executable never shows up in the UI list. This breaks user expectations and removes UI-based permission management.
To confirm the behavior, I created a small reproduction project with both:
a plain executable, and
an identical executable packaged inside an .app bundle.
Only the bundled version appears in System Settings.
Observed Behaviour
1. Plain Executable (from my reproduction project)
When running a plain executable that captures the screen:
macOS displays the normal screen-recording permission prompt.
Before granting permission: screenshots show only the desktop background.
After granting permission: screenshots capture the full display.
The executable does not appear under “Screen & System Audio Recording”.
Even when permission is granted manually (e.g., dragging the executable into the pane), the executable still does not appear, which prevents the user from modifying or revoking the permission through the UI.
If the executable is launched from inside another app (e.g., VS Code, Terminal), the parent app appears in the list instead, not the executable itself.
2. Bundled App Version (from the reproduction project)
I packaged the same code into a simple .app bundle (ScreenCaptureApp.app).
When running the app:
The same permission prompt appears.
Pre-permission screenshots show the desktop background.
Post-permission screenshots capture the full display.
The app does appear under “Screen & System Audio Recording”.
This bundle uses the same underlying executable — the only difference is packaging.
Hypothesis
macOS 26.1 (Tahoe) appears to require app bundles for an item to be shown in the Screen Recording privacy UI.
Plain executables:
still request and receive permission,
still function correctly after permission is granted,
but do not appear in the System Settings list.
This may be an intentional change, undocumented behavior, or a regression.
Reproduction Project
The reproduction project includes:
screen_capture.go A simple Go program that captures screenshots in a loop.
screen_capture_executable Plain executable built from the Go source.
ScreenCaptureApp.app/ App bundle containing the same executable.
build.sh Builds both the plain executable and the app bundle.
Permission reset and TCC testing scripts.
The project demonstrates the behavior consistently.
Steps to Reproduce
Plain Executable
Build:
./build.sh
Reset screen capture permissions:
sudo tccutil reset ScreenCapture
Run:
./screen_capture_executable
Before granting: screenshots show desktop only.
Grant permission when prompted.
After granting: full screenshots.
Executable does not appear in “Screen & System Audio Recording”.
Bundled App
Build (if not already built):
./build.sh
Reset permissions (optional):
sudo tccutil reset ScreenCapture
Run:
open ScreenCaptureApp.app
Before granting: screenshots show desktop.
After granting: full screenshots.
App bundle appears in the System Settings list.
Additional Check
I also tested launching the plain executable as a child process of another executable, similar to how some software architectures work.
Result:
Permission prompt appears
Permission can be granted
Executable still does not appear in the UI, even though TCC tracks it internally → consistent with the plain-executable behaviour.
This reinforces that only app bundles are listed.
Questions for Apple
Is the removal of plain executables from “Screen & System Audio Recording” an intentional change in macOS Tahoe?
If so, does Apple now require all screen-recording capable binaries to be packaged as .app bundles for the UI to display them?
Is there a supported method for making a plain executable (launched by a parent process) appear in the list?
If this is not intentional, what is the recommended path for reporting this as a regression?
Files
Unfortunately, I have discovered the zip file that contains my reproduction project can't be directly uploaded here.
Here is a Google Drive link instead: https://drive.google.com/file/d/1sXsr3Q0g6_UzlOIL54P5wbS7yBkpMJ7A/view?usp=sharing
Thank you for taking the time to review this. Any insight into whether this change is intentional or a regression would be very helpful.
Hello,
I've developed a macOS app with an AutoFill Credential Provider extension that functions as a passkey provider. In the registration flow, I want my app to appear as a passkey provider only when specific conditions are met.
Is there a way to inspect the request from the web before the passkey provider selection list is displayed to the user, determine whether my app can handle it, and then use that result to instruct the OS on whether to include my app in the passkey provider selection list?
Alternatively, is there a way to predefine conditions that must be met before my app is offered as a passkey provider in the selection list?
Thanks!
Topic:
Privacy & Security
SubTopic:
General
Tags:
Extensions
Autofill
Authentication Services
Passkeys in iCloud Keychain
The Core Problem
After Users sign out from the App, the app isn’t properly retrieving the user on second sign in. Instead, it’s treating the user as “Unknown” and saving a new entry in CloudKit and locally. Is there a tutorial aside from 'Juice' that is recent and up to date?
Binary code is associated with the NSUserTrackingUsageDescription deleted at present, but in the revised App privacy will contain NSUserTrackingUsageDescription, I feel very confused, don't know should shouldn't solve.
Is there any way for an iOS app to get a log of all Airdrop transfers originating in all apps on the iOS device e.g. from the last week?
Topic:
Privacy & Security
SubTopic:
General
Dear Apple Developer Technical Support,
We are currently following the official Apple documentation “TN3159: Migrating Sign in with Apple users for an app transfer” to carry out a Sign in with Apple user migration after successfully transferring several apps to a new developer account.
Here is a summary of our situation:
Under the original Apple developer account, we had five apps using Sign in with Apple, grouped under a shared primary app using App Grouping.
Recently, we transferred three of these apps to our new Apple developer account via App Store Connect.
After the transfer, these three apps are no longer associated with the original primary App ID. We reconfigured individual Services IDs for each app in the new account and enabled Sign in with Apple for each.
More than 24 hours have passed since the app transfer was completed.
Now we are attempting to follow the migration process to restore user access via the user.migration flow. Specifically, we are using the following script to request an Apple access token:
url = "https://appleid.apple.com/auth/token"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "client_credentials",
"scope": "user.migration",
"client_id": "com.game.friends.ios.toptop.sea", # New Services ID in the new account
"client_secret": "<JWT signed with new p8 key>"
}
response = requests.post(url, headers=headers, data=data)
However, the API response consistently returns:
{
"error": "invalid_client"
}
We have verified that the following configurations are correct:
The client_secret is generated using the p8 key from the new account, signed with ES256 and correct key_id, team_id, and client_id.
The client_id corresponds to the Services ID created in the new account and properly associated with the migrated app.
The scope is set to user.migration.
The JWT payload contains correct iss, sub, and aud values as per Apple documentation.
The app has been fully transferred and reconfigured more than 24 hours ago.
Problem Summary & Request for Support:
According to Apple’s official documentation:
“After an app is transferred, Apple updates the Sign in with Apple configuration in the background. This can take up to 24 hours. During this time, attempts to authenticate users or validate tokens may fail.”
However, we are still consistently receiving invalid_client errors after the 24-hour waiting period. We suspect one of the following issues:
The transferred apps may still be partially associated with the original App Grouping or primary App ID.
Some Sign in with Apple configuration in Apple’s backend may not have been fully updated after the transfer.
Or the Services ID is not yet fully operational for the transferred apps in the new account.
We kindly request your assistance to:
Verify whether the transferred apps have been completely detached from the original App Grouping and primary App ID.
Confirm whether the new Services IDs under the new account are fully functional and eligible for Sign in with Apple with user.migration scope.
Help identify any remaining configuration or migration issues that may cause the invalid_client error.
If necessary, assist in manually ungrouping or clearing any residual App Grouping relationships affecting the new environment.
We have also generated and retained the original transfer_sub identifiers and are fully prepared to complete the sub mapping once the user.migration flow becomes functional.
Thank you very much for your time and support!
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
Tags:
Sign in with Apple REST API
Sign in with Apple
In the macOS 14.0 SDK, environment and library constraints were introduced, which made defense against common attack vectors relatively simple (especially with the LightWeightCodeRequirements framework added in 14.4).
Now, the application I'm working on must support macOS 13.0 too, so I was looking into alternatives that do work for those operating systems as well.
What I found myself is that the SecCode/SecStaticCode APIs in the Security Framework do offer very similar fashion checks as the LightWeightCodeRequirements framework does:
SecCodeCopySigningInformation can return values like signing identifier, team identifier, code requirement string and so on.
SecStaticCodeCreateWithPath can return a SecStaticCode object to an executable/app bundle on the file system.
Let's say, I would want to protect myself against launchd executable swap.
From macOS 14.0 onward, I would use a Spawn Constraint for this, directly in the launchd.plist file.
Before macOS 14.0, I would create a SecStaticCode object for the executable path found in the launchd.plist, and then examine its SecCodeCopySigningInformation dictionary. If the expectations are met, only then would I execute the launchd.plist-defined executable or connect to it via XPC.
Are these two equivalent? If not, what are the differences?
Can you please give me a hand with importing certificates under MacOS?
I want to connect to Wi-Fi with 802.1X authentication (EAP-TLS) using a certificate that my homebrew application imported into my data protection keychain, but the imported certificate does not show up and I cannot select the certificate.
It also does not show up in the Keychain Access app.
One method I have tried is to import it into the data protection keychain by using the SecItemAdd function and setting kSecUseDataProtectionKeychain to true, but it does not work.
Is there a better way to do this?
ID:
for id in identities {
let identityParams: [String: Any] = [
kSecValueRef as String: id,
kSecReturnPersistentRef as String: true,
kSecUseDataProtectionKeychain as String: true
]
let addIdentityStatus = SecItemAdd(identityParams as CFDictionary, nil)
if addIdentityStatus == errSecSuccess {
print("Successfully added the ID.: \(addIdentityStatus)")
} else {
print("Failed to add the ID.: \(addIdentityStatus)")
}
}
Certificate:
for cert in certificates {
let certParams: [String: Any] = [
kSecValueRef as String: cert,
kSecReturnPersistentRef as String: true,
kSecUseDataProtectionKeychain as String: true
]
let addCertStatus = SecItemAdd(certParams as CFDictionary, nil)
if addCertStatus == errSecSuccess {
print("Successfully added the certificate.: (\(addCertStatus))")
} else {
print("Failed to add the certificate.: (\(addCertStatus))")
}
}
Private key:
for privateKey in keys {
let keyTag = UUID().uuidString.data(using: .utf8)!
let keyParams: [String: Any] = [
kSecAttrApplicationTag as String: keyTag,
kSecValueRef as String: privateKey,
kSecReturnPersistentRef as String: true,
kSecUseDataProtectionKeychain as String: true
]
let addKeyStatus = SecItemAdd(keyParams as CFDictionary, nil)
if addKeyStatus == errSecSuccess {
print("Successfully added the private key.: \(addKeyStatus)")
} else {
print("Failed to add the private key.: \(addKeyStatus)")
}
}
I am developing a daemon-based product that needs a cryptographic, non-spoofable proof of machine identity so a remote management server can grant permissions based on the physical machine.
I was thinking to create a signing key in the Secure Enclave and use a certificate signed by that key as the machine identity. The problem is that the Secure Enclave key I can create is only accessible from user context, while my product runs as a system daemon and must not rely on user processes or launchAgents.
Could you please advise on the recommended Apple-supported approaches for this use case ?
Specifically, Is there a supported way for a system daemon to generate and use an unremovable Secure Enclave key during phases like the pre-logon, that doesn't have non user context (only the my application which created this key/certificate will have permission to use/delete it)
If Secure Enclave access from a daemon is not supported, what Apple-recommended alternatives exist for providing a hardware-backed machine identity for system daemons?
I'd rather avoid using system keychain, as its contents may be removed or used by root privileged users.
The ideal solution would be that each Apple product, would come out with a non removable signing certificate, that represent the machine itself (lets say that the cetificate name use to represent the machine ID), and can be validated by verify that the root signer is "Apple Root CA"