Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.

All subtopics
Posts under Privacy & Security topic

Post

Replies

Boosts

Views

Activity

Privacy & Security Resources
General: Forums topic: Privacy & Security Privacy Resources Security Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
550
Jul ’25
Q&A Summary - Fortify your app: Essential strategies to strengthen security
This is a recap of the Q&A from the Meet with Apple activity Fortify your app: Essential strategies to strengthen security. If you attended the event and asked questions, thank you for coming and participating! If you weren’t able to join us live we hope this recap is useful. Memory Integrity Enforcement (MTE) What is Memory Integrity Enforcement and which devices support it? Memory Integrity Enforcement is supported on A19, A19 Pro, M5, M5 Pro, and M5 Max chips, which power iPhone 17e, the new MacBook Air (M5), and the new MacBook Pro (M5 Pro or M5 Max). Starting in the 26.4 OS versions, applications that enable MTE (checked-allocations) as part of Enhanced Security will also run with MTE enabled in the simulator when running on macOS hardware that supports MTE. How can I use Memory Integrity Enforcement with third-party SDKs? Third-party SDKs linked into your app will generally use the system allocator automatically and benefit from Memory Integrity Enforcement automatically. If there are memory corruption bugs in those SDKs that Memory Integrity Enforcement features like MTE detect and turn into crashes, you'll want to work with the developers of those SDKs to have them fix the underlying bugs. You could use MTE soft mode to avoid having those memory corruptions crash your app while you wait for fixes from the developers, at the cost of the relative reduction in security that entails. Why does my app crash on launch with MTE enabled, with tags showing as 0? Tag-check violations where the ltag (logical tag) is 0 and the atag (actual tag) is non-zero can be caused by code patterns that strip the high bits that the ltag is stored in and fail to restore them before use. Additionally, arm64 binaries produced by older versions of clang may have issues where the tag is incorrectly stripped from the pointer. Recompiling the binary with a recent compiler should remediate the issue. Can I use Memory Integrity Enforcement with older Swift versions? Yes, Memory Integrity Enforcement can be used with any Swift version. Pointer Authentication (PAC) How does Pointer Authentication work and why is it opt-in? PAC is an opt-in feature because although adopting PAC is frequently as easy as turning on the compiler flag, some software is not trivially compatible. For example, while it mostly works in arm64 to memcpy a C++ object, this is invalid and generates fatal exceptions in arm64e. Additionally, PAC is a compile time change as it requires different instructions throughout the program. Pointer authentication makes it more difficult to create a pointer (from an integer) or to modify an existing pointer. This complements technologies such as MTE (which can catch many bound and lifetime errors) and typed allocation (which mitigates the effects of memory re-use). Where are the cryptographic keys for Pointer Authentication stored? The keys used for generating PAC signatures are stored in the CPU itself as specified by the ARM architecture. These keys are ephemeral and can change across process launches and boots, depending on which PAC key is used. The signatures are, however, stored in the upper bits of the pointer itself. How does Pointer Authentication work with Objective-C method swizzling? When you use the functions provided by the ObjC runtime, they ensure that any necessary pointer signing is correctly handled. What deployment targets and OS versions support Pointer Authentication? PAC is tied to the arm64e architecture. arm64e is first supported in iOS 17.4, and generally supported starting with iOS 26 and macOS 26. Universal binaries can be built for arm64e + arm64, and arm64 will be used when arm64e isn't supported. When building the universal binary, both architectures can be compiled for an older deployment target, but keep in mind that arm64e will only be used on newer iOS. How do I enable Pointer Authentication in modular apps? arm64e is indeed required, and every target that contributes binary code that's linked or dynamically loaded into an app does need to have arm64e added as an architecture. When enabling the Enhanced Security capability, Xcode adds the ENABLE_POINTER_AUTHENTICATION build setting (that adds arm64e) as needed, but you may need to add that separately as well. Bounds Safety and Annotations How do bounds safety checks work in Clang? With -fbounds-safety enabled Clang will emit bounds checks wherever pointers are dereferenced or reassigned (exception: assigning to __bidi_indexable does not trigger a bounds check, since __bidi_indexable can track the fact that the pointer is out of bounds and defer the bounds check). If the bounds check fails the program will jump to an instruction that traps the process. Clang uses a combination of static analysis and runtime checks to enforce that pointer bounds are respected. How can I work with libraries that don't have bounds annotations? Forging safe pointers at the boundary (using __unsafe_forge_single etc.) is the recommended approach when interoperating with libraries that do not have bounds annotations, when you want to be explicit about the fact that you're interacting with unsafe code. This makes it easy to grep for "unsafe" in your code base when doing a security audit. If you are confident that the API adheres to a bounds safe interface but simply lacks the annotations, you can redeclare the signature in your local header with added bounds annotations, like this: //--- system_header.h bar_t * /* implicitly __unsafe_indexable */ foo(); //--- project_header.h #include <ptrcheck.h> #include <system_header.h> bar_t * __single foo(); How can I safely pass Swift data to C/C++ functions? This is a great question! Automatically generated wrapper functions that safely unwrap Span types and pass along the pointer to C/C++ is a feature available since Xcode 26 when the experimental feature SafeInteropWrappers is enabled. This requires annotating std::span<T> parameters with __noescape, or pointer parameters with both __noescape and __counted_by/__sized_by, directly in the header or using API notes. Note that this is only safe if Swift can accurately track the lifetime of the unwrapped pointer, which is why the Span wrapper is not generated without the __noescape annotation. Since this is an experimental feature with ongoing development, questions and feedback on the Swift forums are extra welcome to help us shape and stabilize this feature! Continued in next post...
2
0
67
5d
Privacy Resources
General: Forums topic: Privacy & Security Forums tag: Privacy Developer > Security — This also covers privacy topics. App privacy details on the App Store UIKit > Protecting the User’s Privacy documentation Bundle Resources > Privacy manifest files documentation TN3181 Debugging an invalid privacy manifest technote TN3182 Adding privacy tracking keys to your privacy manifest technote TN3183 Adding required reason API entries to your privacy manifest technote TN3184 Adding data collection details to your privacy manifest technote TN3179 Understanding local network privacy technote Handling ITMS-91061: Missing privacy manifest forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
217
Jul ’25
Detecting iOS screen sharing
Hello, Is there any way to detect if the iOS screen is currently being shared via FaceTime or iPhone Mirroring? Our application relies on this information to help ensure that users are not accessing it from one location while physically being in another.
1
0
224
Jul ’25
Unexpected native popup during auth login/signout flow
We are implementing authentication login in our iOS mobile application, and during the sign-in/sign-out process, a native system popup appears with the following message: "This allows the app and website to share information about you." This popup interrupts the user experience, and we are concerned it may cause confusion for end users and negatively impact the adoption of our login flow. We would like clarification on the following points: What triggers this popup during the authentication process? Are there any recommended configurations or approaches to suppress or avoid this dialog? If the popup cannot be avoided, what best practices are suggested to ensure a clear and seamless user experience? Our objective is to provide a smooth, user-friendly authentication flow without unexpected system interruptions.
0
0
162
Aug ’25
Cannot update ASCredentialIdentityStore while device locked
Our product includes a background sync process that synchronizes credentials between devices. We need to update ASCredentialIdentityStore when credentials are changed, we have noticed that the ASCredentialIdentityStore.shared.saveCredentialIdentities() fails to run when the device is locked. Is it possible to update ASCredentialIdentityStore when the device is locked?
0
0
89
Apr ’25
Appstore submission rejected - Privacy
Please correct the following issues and upload a new binary to App Store Connect. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics”, which includes FirebaseCoreDiagnostics, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/FBLPromises.framework/FBLPromises”, which includes FBLPromises, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/GoogleDataTransport.framework/GoogleDataTransport”, which includes GoogleDataTransport, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. our app is .NET MAUI app so we already addressed this by adding privacyinfo.xcprivacy privacy manifest under platform/ios/resources but still get flagged for this <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSPrivacyTracking</key> <false/> <key>NSPrivacyTrackingDomains</key> <array/> <key>NSPrivacyAccessedAPITypes</key> <array> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryFileTimestamp</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>C617.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategorySystemBootTime</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>35F9.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryDiskSpace</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>E174.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryUserDefaults</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>CA92.1</string> </array> </dict> </array> <key>NSPrivacyCollectedDataTypes</key> <array/> </dict> </plist>
1
0
154
Apr ’25
SecItem: Fundamentals
I regularly help developers with keychain problems, both here on DevForums and for my Day Job™ in DTS. Many of these problems are caused by a fundamental misunderstanding of how the keychain works. This post is my attempt to explain that. I wrote it primarily so that Future Quinn™ can direct folks here rather than explain everything from scratch (-: If you have questions or comments about any of this, put them in a new thread and apply the Security tag so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" SecItem: Fundamentals or How I Learned to Stop Worrying and Love the SecItem API The SecItem API seems very simple. After all, it only has four function calls, how hard can it be? In reality, things are not that easy. Various factors contribute to making this API much trickier than it might seem at first glance. This post explains the fundamental underpinnings of the keychain. For information about specific issues, see its companion post, SecItem: Pitfalls and Best Practices. Keychain Documentation Your basic starting point should be Keychain Items. If your code runs on the Mac, also read TN3137 On Mac keychain APIs and implementations. Read the doc comments in <Security/SecItem.h>. In many cases those doc comments contain critical tidbits. When you read keychain documentation [1] and doc comments, keep in mind that statements specific to iOS typically apply to iPadOS, tvOS, and watchOS as well (r. 102786959). Also, they typically apply to macOS when you target the data protection keychain. Conversely, statements specific to macOS may not apply when you target the data protection keychain. [1] Except TN3137, which is very clear about this (-: Caveat Mac Developer macOS supports two different keychain implementations: the original file-based keychain and the iOS-style data protection keychain. IMPORTANT If you’re able to use the data protection keychain, do so. It’ll make your life easier. See the Careful With that Shim, Mac Developer section of SecItem: Pitfalls and Best Practices for more about this. TN3137 On Mac keychain APIs and implementations explains this distinction. It also says: The file-based keychain is on the road to deprecation. This is talking about the implementation, not any specific API. The SecItem API can’t be deprecated because it works with both the data protection keychain and the file-based keychain. However, Apple has deprecated many APIs that are specific to the file-based keychain, for example, SecKeychainCreate. TN3137 also notes that some programs, like launchd daemons, can’t use the file-based keychain. If you’re working on such a program then you don’t have to worry about the deprecation of these file-based keychain APIs. You’re already stuck with the file-based keychain implementation, so using a deprecated file-based keychain API doesn’t make things worse. The Four Freedoms^H^H^H^H^H^H^H^H Functions The SecItem API contains just four functions: SecItemAdd(_:_:) SecItemCopyMatching(_:_:) SecItemUpdate(_:_:) SecItemDelete(_:) These directly map to standard SQL database operations: SecItemAdd(_:_:) maps to INSERT. SecItemCopyMatching(_:_:) maps to SELECT. SecItemUpdate(_:_:) maps to UPDATE. SecItemDelete(_:) maps to DELETE. You can think of each keychain item class (generic password, certificate, and so on) as a separate SQL table within the database. The rows of that table are the individual keychain items for that class and the columns are the attributes of those items. Note Except for the digital identity class, kSecClassIdentity, where the values are split across the certificate and key tables. See Digital Identities Aren’t Real in SecItem: Pitfalls and Best Practices. This is not an accident. The data protection keychain is actually implemented as an SQLite database. If you’re curious about its structure, examine it on the Mac by pointing your favourite SQLite inspection tool — for example, the sqlite3 command-line tool — at the keychain database in ~/Library/Keychains/UUU/keychain-2.db, where UUU is a UUID. WARNING Do not depend on the location and structure of this file. These have changed in the past and are likely to change again in the future. If you embed knowledge of them into a shipping product, it’s likely that your product will have binary compatibility problems at some point in the future. The only reason I’m mentioning them here is because I find it helpful to poke around in the file to get a better understanding of how the API works. For information about which attributes are supported by each keychain item class — that is, what columns are in each table — see the Note box at the top of Item Attribute Keys and Values. Alternatively, look at the Attribute Key Constants doc comment in <Security/SecItem.h>. Uniqueness A critical part of the keychain model is uniqueness. How does the keychain determine if item A is the same as item B? It turns out that this is class dependent. For each keychain item class there is a set of attributes that form the uniqueness constraint for items of that class. That is, if you try to add item A where all of its attributes are the same as item B, the add fails with errSecDuplicateItem. For more information, see the errSecDuplicateItem page. It has lists of attributes that make up this uniqueness constraint, one for each class. These uniqueness constraints are a major source of confusion, as discussed in the Queries and the Uniqueness Constraints section of SecItem: Pitfalls and Best Practices. Parameter Blocks Understanding The SecItem API is a classic ‘parameter block’ API. All of its inputs are dictionaries, and you have to know which properties to set in each dictionary to achieve your desired result. Likewise for when you read properties in output dictionaries. There are five different property groups: The item class property, kSecClass, determines the class of item you’re operating on: kSecClassGenericPassword, kSecClassCertificate, and so on. The item attribute properties, like kSecAttrAccessGroup, map directly to keychain item attributes. The search properties, like kSecMatchLimit, control how the system runs a query. The return type properties, like kSecReturnAttributes, determine what values the query returns. The value type properties, like kSecValueRef perform multiple duties, as explained below. There are other properties that perform a variety of specific functions. For example, kSecUseDataProtectionKeychain tells macOS to use the data protection keychain instead of the file-based keychain. These properties are hard to describe in general; for the details, see the documentation for each such property. Inputs Each of the four SecItem functions take dictionary input parameters of the same type, CFDictionary, but these dictionaries are not the same. Different dictionaries support different property groups: The first parameter of SecItemAdd(_:_:) is an add dictionary. It supports all property groups except the search properties. The first parameter of SecItemCopyMatching(_:_:) is a query and return dictionary. It supports all property groups. The first parameter of SecItemUpdate(_:_:) is a pure query dictionary. It supports all property groups except the return type properties. Likewise for the only parameter of SecItemDelete(_:). The second parameter of SecItemUpdate(_:_:) is an update dictionary. It supports the item attribute and value type property groups. Outputs Two of the SecItem functions, SecItemAdd(_:_:) and SecItemCopyMatching(_:_:), return values. These output parameters are of type CFTypeRef because the type of value you get back depends on the return type properties you supply in the input dictionary: If you supply a single return type property, except kSecReturnAttributes, you get back a value appropriate for that return type. If you supply multiple return type properties or kSecReturnAttributes, you get back a dictionary. This supports the item attribute and value type property groups. To get a non-attribute value from this dictionary, use the value type property that corresponds to its return type property. For example, if you set kSecReturnPersistentRef in the input dictionary, use kSecValuePersistentRef to get the persistent reference from the output dictionary. In the single item case, the type of value you get back depends on the return type property and the keychain item class: For kSecReturnData you get back the keychain item’s data. This makes most sense for password items, where the data holds the password. It also works for certificate items, where you get back the DER-encoded certificate. Using this for key items is kinda sketchy. If you want to export a key, called SecKeyCopyExternalRepresentation. Using this for digital identity items is nonsensical. For kSecReturnRef you get back an object reference. This only works for keychain item classes that have an object representation, namely certificates, keys, and digital identities. You get back a SecCertificate, a SecKey, or a SecIdentity, respectively. For kSecReturnPersistentRef you get back a data value that holds the persistent reference. Value Type Subtleties There are three properties in the value type property group: kSecValueData kSecValueRef kSecValuePersistentRef Their semantics vary based on the dictionary type. For kSecValueData: In an add dictionary, this is the value of the item to add. For example, when adding a generic password item (kSecClassGenericPassword), the value of this key is a Data value containing the password. This is not supported in a query dictionary. In an update dictionary, this is the new value for the item. For kSecValueRef: In add and query dictionaries, the system infers the class property and attribute properties from the supplied object. For example, if you supply a certificate object (SecCertificate, created using SecCertificateCreateWithData), the system will infer a kSecClass value of kSecClassCertificate and various attribute values, like kSecAttrSerialNumber, from that certificate object. This is not supported in an update dictionary. For kSecValuePersistentRef: For query dictionaries, this uniquely identifies the item to operate on. This is not supported in add and update dictionaries. Revision History 2025-05-28 Expanded the Caveat Mac Developer section to cover some subtleties associated with the deprecation of the file-based keychain. 2023-09-12 Fixed various bugs in the revision history. Added a paragraph explaining how to determine which attributes are supported by each keychain item class. 2023-02-22 Made minor editorial changes. 2023-01-28 First posted.
0
0
4.4k
May ’25
DeviceCheck - Device Validation Endpoint not working
We have been having very high response times in device check device validation service (https://developer.apple.com/documentation/devicecheck/accessing-and-modifying-per-device-data#Create-the-payload-for-a-device-validation-request) since 17 July at 19:10hs GMT. The service information page says the service was running in green status but that isn't the case and we currenly have stop consuming it. Is it being looked at? Are you aware of this issue? Can you give us an estimate of when it should be working correctly?
1
0
807
Jul ’25
Problem Saving a ASPasskeyCredentialIdentity
Hi I'm developing an app that autofills Passkeys. The app allows the user to authenticate to their IdP to obtain an access token. Using the token the app fetches from <server>/attestation/options. The app will generate a Passkey credential using a home-grown module - the extension has no involvement, neither does ASAuthorizationSecurityKeyPublicKeyCredentialProvider. I can confirm the passkey does get created. Next the credential is posted to <server>/attestation/results with the response JSON being parsed and used to create a ASPasskeyCredentialIdentity - a sample of the response JSON is attached. Here is my save function: static func save(authenticator: AuthenticatorInfo) async throws { guard let credentialID = Data(base64URLEncoded: authenticator.attributes.credentialId) else { throw AuthenticatorError.invalidEncoding("Credential ID is not a valid Base64URL string.") } guard let userHandle = authenticator.userId.data(using: .utf8) else { throw AuthenticatorError.invalidEncoding("User handle is not a valid UTF-8 string.") } let identity = ASPasskeyCredentialIdentity( relyingPartyIdentifier: authenticator.attributes.rpId, userName: authenticator.userId, // This is what the user sees in the UI credentialID: credentialID, userHandle: userHandle, recordIdentifier: authenticator.id ) try await ASCredentialIdentityStore.shared.saveCredentialIdentities([identity]) } Although no error occurs, I don't get any identities returned when I call this method: let identities = await ASCredentialIdentityStore.shared.credentialIdentities( forService: nil, credentialIdentityTypes: [.passkey] ) Here is the Info.plist in the Extension: <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>ASCredentialProviderExtensionCapabilities</key> <dict> <key>ProvidesPasskeys</key> <true/> </dict> <key>ASCredentialProviderExtensionShowsConfigurationUI</key> <true/> </dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.authentication-services-credential-provider-ui</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).CredentialProviderViewController</string> </dict> </dict> </plist> The entitlements are valid and the app and extension both support the same group. I'm stumped as to why the identity is not getting saved. Any ideas and not getting retrieved. attestationResult.json
1
0
428
Jan ’26
AASA not being fetched immediately upon app install
Hi Apple Devs, For our app, we utilize passkeys for account creation (not MFA). This is mainly for user privacy, as there is 0 PII associated with passkey account creation, but it additionally also satisfies the 4.8: Login Services requirement for the App Store. However, we're getting blocked in Apple Review. Because the AASA does not get fetched immediately upon app install, the reviewers are not able to create an account immediately via passkeys, and then they reject the build. I'm optimistic I can mitigate the above. But even if we pass Apple Review, this is a pretty catastrophic issue for user security and experience. There are reports that 5% of users cannot create passkeys immediately (https://developer.apple.com/forums/thread/756740). That is a nontrivial amount of users, and this large of an amount distorts how app developers design onboarding and authentication flows towards less secure experiences: App developers are incentivized to not require MFA setup on account creation because requiring it causes significant churn, which is bad for user security. If they continue with it anyways, for mitigation, developers are essentially forced to add in copy into their app saying something along the lines of "We have no ability to force Apple to fetch the config required to continue sign up, so try again in a few minutes, you'll just have to wait." You can't even implement a fallback method. There's no way to check if the AASA is available before launching the ASAuthorizationController so you can't mitigate a portion of users encountering an error!! Any app that wants to use the PRF extension to encrypt core functionality (again, good for user privacy) simply cannot exist because the app simply does not work for an unspecified amount of time for a nontrivial portion of users. It feels like a. Apple should provide a syscall API that we can call to force SWCD to verify the AASA or b. implement a config based on package name for the app store such that the installation will immediately include a verified AASA from Apple's CDN. Flicking the config on would require talking with Apple. If this existed, this entire class of error would go away. It feels pretty shocking that there isn't a mitigation in place for this already given that it incentivizes app developers to pursue strictly less secure and less private authentication practices.
0
0
392
Aug ’25
App transfer- get transfer {"error":"invalid_request"}
Migrating APP and users, obtaining the user's transfer_sub, an exception occurred: {"error":"invalid_request"} `POST /auth/usermigrationinfo HTTP/1.1 Host: appleid.apple.com Content-Type: application/x-www-form-urlencoded Authorization: Bearer {access_token} sub={sub}&target={recipient_team_id}&client_id={client_id}&client_secret={client_secret} The specific request is as follows: 15:56:20.858 AppleService - --> POST https://appleid.apple.com/auth/usermigrationinfo 15:56:20.858 AppleService - Content-Type: application/x-www-form-urlencoded 15:56:20.858 AppleService - Content-Length: 395 15:56:20.858 AppleService - Authorization: Bearer a56a8828048af48c0871e73b55d8910aa.0.rzvs.96uUcy1KBqo34Kj8qrPb4w 15:56:20.858 AppleService - 15:56:20.858 AppleService - sub=001315.1535dbadc15b472987acdf634719a06a.0600&target=WLN67KBBV8&client_id=com.hawatalk.live&client_secret=eyJraWQiOiIzODg5U1ZXNDM5IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJRMzlUU1BHMjk3IiwiaWF0IjoxNzU1MDcxNzc5LCJleHAiOjE3NTUwNzUzNzksImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJzdWIiOiJjb20uaGF3YXRhbGsubGl2ZSJ9.8i9RYIcepuIiEqOMu1OOAlmmjnB84AJueel21gNapiNa9pr3498Zkj8J5MUIzvvnvsvUJkKQjp_VvnsG_IIrTA 15:56:20.859 AppleService - --> END POST (395-byte body) 15:56:21.675 AppleService - <-- 400 Bad Request https://appleid.apple.com/auth/usermigrationinfo(816ms) 15:56:21.675 AppleService - Server: Apple 15:56:21.675 AppleService - Date: Wed, 13 Aug 2025 07:56:22 GMT 15:56:21.675 AppleService - Content-Type: application/json;charset=UTF-8 15:56:21.675 AppleService - Content-Length: 27 15:56:21.675 AppleService - Connection: keep-alive 15:56:21.675 AppleService - Pragma: no-cache 15:56:21.675 AppleService - Cache-Control: no-store 15:56:21.676 AppleService - 15:56:21.676 AppleService - {"error":"invalid_request"} 15:56:21.676 AppleService - <-- END HTTP (27-byte body) ` Current Team ID: Q39TSPG297 Recipient Team ID: WLN67KBBV8 CLIENT_ID: com.hawatalk.live
0
0
192
Aug ’25
Sudden Increase of Hard Bounce with privaterelay emails
We have been sending emails through Sparkpost via Braze inc. to the Apple Private Relay users with "@privaterelay.appleid.com" starting from around June 20th or so. Upon August 9th 06:00 UTC, we have noticed a sudden increase of "Hard Bounce" for nearly 20,000 users using the Apple's private relay email address, rendering the email sending useless for these customers. We have been constantly been able to send them emails, including just before this timeframe (e.g. August 9th 03:00 UTC), so it was a very sudden purge of the user data that has been done without our consent. From a business perspective, this hurts a lot for the un-sendable users since we have no way of contacting them if not for the private address. We are desperate to know what has happened for these customers that has been "hard bounced". We are suspecting that it should be tied to the private email and the users primary email (or user data's) tie in the Apple server being gone, but not sure enough since there is no such documentation nor any way to acknowledge what has happened anywhere. We will provide any information possible for resolving. Thank you.
0
0
326
Aug ’25
Mac App Store app triggers "cannot verify free of malware" alert when opening as default app
My app Mocawave is a music player distributed through the Mac App Store. It declares specific audio document types (public.mp3, com.microsoft.waveform-audio, public.mpeg-4-audio, public.aac-audio) in its CFBundleDocumentTypes with a Viewer role. When a user sets Mocawave as the default app for audio files and double-clicks an MP3 downloaded from the internet (which has the com.apple.quarantine extended attribute), macOS displays the alert: "Apple could not verify [filename] is free of malware that may harm your Mac or compromise your privacy." This does not happen when: Opening the same file via NSOpenPanel from within the app Opening the same file with Apple's Music.app or QuickTime Player The app is: Distributed through the Mac App Store Sandboxed (com.apple.security.app-sandbox) Uses com.apple.security.files.user-selected.read-write entitlement The file being opened is a regular audio file (MP3), not an executable. Since the app is sandboxed and distributed through the App Store, I expected it to have sufficient trust to open quarantined data files without triggering Gatekeeper warnings — similar to how Music.app and QuickTime handle them. Questions: Is there a specific entitlement or Info.plist configuration that allows a sandboxed Mac App Store app to open quarantined audio files without this alert? Is this expected behavior for third-party App Store apps, or could this indicate a misconfiguration on my end? Environment: macOS 15 (Sequoia), app built with Swift/SwiftUI, targeting macOS 13+.
2
0
188
Feb ’26
Fraud prevention using Device Check when publishing multiple apps
I would like to confirm about fraud prevention using Device Check when publishing multiple apps. If the Team ID and Key ID are the same, will the values be shared across all apps with Device Check? With Device Check, only two keys can be created per developer account, and these two are primarily intended for key renewal in case of a leak, rather than for assigning different keys to each app, correct? If both 1 and 2 are correct, does that mean that Device Check should not be used to manage "one-time-only rewards per device" when offering them across multiple apps? Thank you very much for your confirmation.
0
0
211
Apr ’25
Apple SignIn configuration change from Group to Primary ID
I have two applications, and I recently decided to add the Apple Sign In feature. Initially, I configured it for one of the apps as the Primary ID for this feature. Everything worked well, and I decided to add it to the second app. I made a mistake and used the First app as Primary ID using the "Group with an existing primary App ID" flag. Now, when I sign in using the second app, I don't see it in the list of apps in iPhone Settings for Apple Sign In; I only see the primary app. And with that, I no longer see a prompt for sharing/hiding email, and I am unable to revoke credentials correctly. I decided to change the Second app's Sign-in config and set it as the Primary ID for the feature. I was hoping to get two apps independent for the SignIn. However, it doesn't seem to make a difference. The second app behaves the same way, as long as the first app used SignIn, the second one always thinks that the user has already used that feature and never shows the correct prompt. Is there something I missed after changing the Configuration?
0
0
172
Jul ’25
iPad App Suggestions - Api Security
Hi , I have a requirement like, Develop an app for iPad and app uses .net core apis. App will be in kiosk mode, and app doesn't have any type of authentication even OTP also. As the apis will be publishing to all over internet, how can we achieve security to apis? Kindly provide suggestions for this implementation
1
0
223
Sep ’25
Authentication using MSAL library in offline mode
Hi. We are trying to get the access token before calling any API. The app can go in bad network areas but the token acquisition keeps happening for the network call. The devices are managed devices which means it has some policies installed. We are using MSAL lib for the authentication and we are investigating from that angle too but the below error seems to be coming from apple authentication which needs our attention. ========================================== LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=68, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} Attempt to map database failed: permission was denied. This attempt will not be retried. Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=68, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} Failed to get application extension record: Error Domain=NSOSStatusErrorDomain Code=-54 "(null)" ASAuthorizationController credential request failed with error: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1003 "(null)" ========================================== This happens mostly when we switches the network or keep the device in no or low network area. This comes sometimes when app goes in background too. Just trying to give as much as information I could. Any lead would be highly appreciated. Thank you
0
0
139
Apr ’25
App Attest attestationData request fails with 400 Bad Request (no X-Request-ID)
Hello Apple Team We are integrating App Attest with our backend and seeing a 400 Bad Request response when calling the attestation endpoint. The issue is that the response does not include an X-Request-ID or JSON error payload with id and code, which makes it hard to diagnose. Instead, it only returns a receipt blob. Request Details URL: https://data-development.appattest.apple.com/v1/attestationData Request Headers: Authorization: eyJraWQiOiI0RjVLSzRGV1JaIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJOOVNVR1pNNjdRIiwiZXhwIjoxNzU3MDUxNTYwLCJpYXQiOjE3NTcwNDc5NjB9.MEQCIF236MqPCl6Vexg7RcPUMK8XQeACXogldnpuiNnGQnzgAiBQqASdbJ64g58xfWGpbzY3iohvxBSO5U5ZE3l87JjfmQ Content-Type: application/octet-stream Request Body: (Binary data, logged as [B@59fd7d35) Response Status: 400 Bad Request Response Headers: Date: Fri, 05 Sep 2025 04:52:40 GMT x-b3-traceid: 4c42e18094022424 x-b3-spanid: 4c42e18094022424 Response Body (truncated): "receipt": h'308006092A864886F70D01070... Problem The response does not include X-Request-ID. The response does not include JSON with id or code. Only a receipt blob is returned. Questions Can the x-b3-traceid be used by Apple to trace this failed request internally? Is it expected for some failures to return only a receipt blob without X-Request-ID? How should we interpret this error so we can handle it properly in production? Thanks in advance for your guidance.
1
0
511
Sep ’25
Critical Privacy and Security Issue: Spotlight disregards explicit exclusions and exposes user files
Apple has repeatedly ignored my reports about a critical privacy issue in Spotlight on macOS 26, and the problem persists in version 26.3 RC. This is not a minor glitch, it is a fundamental breach of user trust and privacy. Several aspects of Spotlight fail to respect user settings: • Hidden apps still exposed: In the Apps section (Cmd+1), Spotlight continues to display apps marked with the hidden flag, even though they should remain invisible. • Clipboard reactivation: The clipboard feature repeatedly turns itself back on after logout or restart, despite being explicitly disabled by the user. • Excluded files revealed: Most concerning, Spotlight exposes files in Suggestions and Recents (Cmd+3) even when those files are explicitly excluded under System Settings > Spotlight > Search Privacy. This behavior directly violates user expectations and system settings. It is not only a major privacy issue but also a security risk, since sensitive files can be surfaced without consent. Apple must address this immediately. Users rely on Spotlight to respect their privacy configurations, and the current behavior undermines both trust and security.
2
0
485
Feb ’26
Implementing Script Attachment in a Sandboxed App
Script attachment enables advanced users to create powerful workflows that start in your app. NSUserScriptTask lets you implement script attachment even if your app is sandboxed. This post explains how to set that up. IMPORTANT Most sandboxed apps are sandboxed because they ship on the Mac App Store [1]. While I don’t work for App Review, and thus can’t make definitive statements on their behalf, I want to be clear that NSUserScriptTask is intended to be used to implement script attachment, not as a general-purpose sandbox bypass mechanism. If you have questions or comments, please put them in a new thread. Place it in the Privacy &amp; Security &gt; General subtopic, and tag it with App Sandbox. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] Most but not all. There are good reasons to sandbox your app even if you distribute it directly. See The Case for Sandboxing a Directly Distributed App. Implementing Script Attachment in a Sandboxed App Some apps support script attachment, that is, they allow a user to configure the app to run a script when a particular event occurs. For example: A productivity app might let a user automate repetitive tasks by configuring a toolbar button to run a script. A mail client might let a user add a script that processes incoming mail. When adding script attachment to your app, consider whether your scripting mechanism is internal or external: An internal script is one that only affects the state of the app. A user script is one that operates as the user, that is, it can change the state of other apps or the system as a whole. Supporting user scripts in a sandboxed app is a conundrum. The App Sandbox prevents your app from changing the state of other apps, but that’s exactly what your app needs to do to support user scripts. NSUserScriptTask resolves this conundrum. Use it to run scripts that the user has placed in your app’s Script folder. Because these scripts were specifically installed by the user, their presence indicates user intent and the system runs them outside of your app’s sandbox. Provide easy access to your app’s Script folder Your application’s Scripts folder is hidden within ~/Library. To make it easier for the user to add scripts, add a button or menu item that uses NSWorkspace to show it in the Finder: let scriptsDir = try FileManager.default.url(for: .applicationScriptsDirectory, in: .userDomainMask, appropriateFor: nil, create: true) NSWorkspace.shared.activateFileViewerSelecting([scriptsDir]) Enumerate the available scripts To show a list of scripts to the user, enumerate the Scripts folder: let scriptsDir = try FileManager.default.url(for: .applicationScriptsDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let scriptURLs = try FileManager.default.contentsOfDirectory(at: scriptsDir, includingPropertiesForKeys: [.localizedNameKey]) let scriptNames = try scriptURLs.map { url in return try url.resourceValues(forKeys: [.localizedNameKey]).localizedName! } This uses .localizedNameKey to get the name to display to the user. This takes care of various edge cases, for example, it removes the file name extension if it’s hidden. Run a script To run a script, instantiate an NSUserScriptTask object and call its execute() method: let script = try NSUserScriptTask(url: url) try await script.execute() Run a script with arguments NSUserScriptTask has three subclasses that support additional functionality depending on the type of the script. Use the NSUserUnixTask subsclass to run a Unix script and: Supply command-line arguments. Connect pipes to stdin, stdout, and stderr. Get the termination status. Use the NSUserAppleScriptTask subclass to run an AppleScript, executing either the run handler or a custom Apple event. Use the NSUserAutomatorTask subclass to run an Automator workflow, supplying an optional input. To determine what type of script you have, try casting it to each of the subclasses: let script: NSUserScriptTask = … switch script { case let script as NSUserUnixTask: … use Unix-specific functionality … case let script as NSUserAppleScriptTask: … use AppleScript-specific functionality … case let script as NSUserAutomatorTask: … use Automatic-specific functionality … default: … use generic functionality … }
0
0
988
Aug ’25
Privacy & Security Resources
General: Forums topic: Privacy & Security Privacy Resources Security Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
550
Activity
Jul ’25
Q&A Summary - Fortify your app: Essential strategies to strengthen security
This is a recap of the Q&amp;A from the Meet with Apple activity Fortify your app: Essential strategies to strengthen security. If you attended the event and asked questions, thank you for coming and participating! If you weren’t able to join us live we hope this recap is useful. Memory Integrity Enforcement (MTE) What is Memory Integrity Enforcement and which devices support it? Memory Integrity Enforcement is supported on A19, A19 Pro, M5, M5 Pro, and M5 Max chips, which power iPhone 17e, the new MacBook Air (M5), and the new MacBook Pro (M5 Pro or M5 Max). Starting in the 26.4 OS versions, applications that enable MTE (checked-allocations) as part of Enhanced Security will also run with MTE enabled in the simulator when running on macOS hardware that supports MTE. How can I use Memory Integrity Enforcement with third-party SDKs? Third-party SDKs linked into your app will generally use the system allocator automatically and benefit from Memory Integrity Enforcement automatically. If there are memory corruption bugs in those SDKs that Memory Integrity Enforcement features like MTE detect and turn into crashes, you'll want to work with the developers of those SDKs to have them fix the underlying bugs. You could use MTE soft mode to avoid having those memory corruptions crash your app while you wait for fixes from the developers, at the cost of the relative reduction in security that entails. Why does my app crash on launch with MTE enabled, with tags showing as 0? Tag-check violations where the ltag (logical tag) is 0 and the atag (actual tag) is non-zero can be caused by code patterns that strip the high bits that the ltag is stored in and fail to restore them before use. Additionally, arm64 binaries produced by older versions of clang may have issues where the tag is incorrectly stripped from the pointer. Recompiling the binary with a recent compiler should remediate the issue. Can I use Memory Integrity Enforcement with older Swift versions? Yes, Memory Integrity Enforcement can be used with any Swift version. Pointer Authentication (PAC) How does Pointer Authentication work and why is it opt-in? PAC is an opt-in feature because although adopting PAC is frequently as easy as turning on the compiler flag, some software is not trivially compatible. For example, while it mostly works in arm64 to memcpy a C++ object, this is invalid and generates fatal exceptions in arm64e. Additionally, PAC is a compile time change as it requires different instructions throughout the program. Pointer authentication makes it more difficult to create a pointer (from an integer) or to modify an existing pointer. This complements technologies such as MTE (which can catch many bound and lifetime errors) and typed allocation (which mitigates the effects of memory re-use). Where are the cryptographic keys for Pointer Authentication stored? The keys used for generating PAC signatures are stored in the CPU itself as specified by the ARM architecture. These keys are ephemeral and can change across process launches and boots, depending on which PAC key is used. The signatures are, however, stored in the upper bits of the pointer itself. How does Pointer Authentication work with Objective-C method swizzling? When you use the functions provided by the ObjC runtime, they ensure that any necessary pointer signing is correctly handled. What deployment targets and OS versions support Pointer Authentication? PAC is tied to the arm64e architecture. arm64e is first supported in iOS 17.4, and generally supported starting with iOS 26 and macOS 26. Universal binaries can be built for arm64e + arm64, and arm64 will be used when arm64e isn't supported. When building the universal binary, both architectures can be compiled for an older deployment target, but keep in mind that arm64e will only be used on newer iOS. How do I enable Pointer Authentication in modular apps? arm64e is indeed required, and every target that contributes binary code that's linked or dynamically loaded into an app does need to have arm64e added as an architecture. When enabling the Enhanced Security capability, Xcode adds the ENABLE_POINTER_AUTHENTICATION build setting (that adds arm64e) as needed, but you may need to add that separately as well. Bounds Safety and Annotations How do bounds safety checks work in Clang? With -fbounds-safety enabled Clang will emit bounds checks wherever pointers are dereferenced or reassigned (exception: assigning to __bidi_indexable does not trigger a bounds check, since __bidi_indexable can track the fact that the pointer is out of bounds and defer the bounds check). If the bounds check fails the program will jump to an instruction that traps the process. Clang uses a combination of static analysis and runtime checks to enforce that pointer bounds are respected. How can I work with libraries that don't have bounds annotations? Forging safe pointers at the boundary (using __unsafe_forge_single etc.) is the recommended approach when interoperating with libraries that do not have bounds annotations, when you want to be explicit about the fact that you're interacting with unsafe code. This makes it easy to grep for "unsafe" in your code base when doing a security audit. If you are confident that the API adheres to a bounds safe interface but simply lacks the annotations, you can redeclare the signature in your local header with added bounds annotations, like this: //--- system_header.h bar_t * /* implicitly __unsafe_indexable */ foo(); //--- project_header.h #include &lt;ptrcheck.h&gt; #include &lt;system_header.h&gt; bar_t * __single foo(); How can I safely pass Swift data to C/C++ functions? This is a great question! Automatically generated wrapper functions that safely unwrap Span types and pass along the pointer to C/C++ is a feature available since Xcode 26 when the experimental feature SafeInteropWrappers is enabled. This requires annotating std::span&lt;T&gt; parameters with __noescape, or pointer parameters with both __noescape and __counted_by/__sized_by, directly in the header or using API notes. Note that this is only safe if Swift can accurately track the lifetime of the unwrapped pointer, which is why the Span wrapper is not generated without the __noescape annotation. Since this is an experimental feature with ongoing development, questions and feedback on the Swift forums are extra welcome to help us shape and stabilize this feature! Continued in next post...
Replies
2
Boosts
0
Views
67
Activity
5d
Privacy Resources
General: Forums topic: Privacy & Security Forums tag: Privacy Developer > Security — This also covers privacy topics. App privacy details on the App Store UIKit > Protecting the User’s Privacy documentation Bundle Resources > Privacy manifest files documentation TN3181 Debugging an invalid privacy manifest technote TN3182 Adding privacy tracking keys to your privacy manifest technote TN3183 Adding required reason API entries to your privacy manifest technote TN3184 Adding data collection details to your privacy manifest technote TN3179 Understanding local network privacy technote Handling ITMS-91061: Missing privacy manifest forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Replies
0
Boosts
0
Views
217
Activity
Jul ’25
Detecting iOS screen sharing
Hello, Is there any way to detect if the iOS screen is currently being shared via FaceTime or iPhone Mirroring? Our application relies on this information to help ensure that users are not accessing it from one location while physically being in another.
Replies
1
Boosts
0
Views
224
Activity
Jul ’25
Unexpected native popup during auth login/signout flow
We are implementing authentication login in our iOS mobile application, and during the sign-in/sign-out process, a native system popup appears with the following message: "This allows the app and website to share information about you." This popup interrupts the user experience, and we are concerned it may cause confusion for end users and negatively impact the adoption of our login flow. We would like clarification on the following points: What triggers this popup during the authentication process? Are there any recommended configurations or approaches to suppress or avoid this dialog? If the popup cannot be avoided, what best practices are suggested to ensure a clear and seamless user experience? Our objective is to provide a smooth, user-friendly authentication flow without unexpected system interruptions.
Replies
0
Boosts
0
Views
162
Activity
Aug ’25
Cannot update ASCredentialIdentityStore while device locked
Our product includes a background sync process that synchronizes credentials between devices. We need to update ASCredentialIdentityStore when credentials are changed, we have noticed that the ASCredentialIdentityStore.shared.saveCredentialIdentities() fails to run when the device is locked. Is it possible to update ASCredentialIdentityStore when the device is locked?
Replies
0
Boosts
0
Views
89
Activity
Apr ’25
Appstore submission rejected - Privacy
Please correct the following issues and upload a new binary to App Store Connect. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/FirebaseCoreDiagnostics.framework/FirebaseCoreDiagnostics”, which includes FirebaseCoreDiagnostics, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/FBLPromises.framework/FBLPromises”, which includes FBLPromises, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/GoogleDataTransport.framework/GoogleDataTransport”, which includes GoogleDataTransport, an SDK that was identified in the documentation as a commonly used third-party SDK. If a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. our app is .NET MAUI app so we already addressed this by adding privacyinfo.xcprivacy privacy manifest under platform/ios/resources but still get flagged for this <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSPrivacyTracking</key> <false/> <key>NSPrivacyTrackingDomains</key> <array/> <key>NSPrivacyAccessedAPITypes</key> <array> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryFileTimestamp</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>C617.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategorySystemBootTime</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>35F9.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryDiskSpace</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>E174.1</string> </array> </dict> <dict> <key>NSPrivacyAccessedAPIType</key> <string>NSPrivacyAccessedAPICategoryUserDefaults</string> <key>NSPrivacyAccessedAPITypeReasons</key> <array> <string>CA92.1</string> </array> </dict> </array> <key>NSPrivacyCollectedDataTypes</key> <array/> </dict> </plist>
Replies
1
Boosts
0
Views
154
Activity
Apr ’25
SecItem: Fundamentals
I regularly help developers with keychain problems, both here on DevForums and for my Day Job™ in DTS. Many of these problems are caused by a fundamental misunderstanding of how the keychain works. This post is my attempt to explain that. I wrote it primarily so that Future Quinn™ can direct folks here rather than explain everything from scratch (-: If you have questions or comments about any of this, put them in a new thread and apply the Security tag so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" SecItem: Fundamentals or How I Learned to Stop Worrying and Love the SecItem API The SecItem API seems very simple. After all, it only has four function calls, how hard can it be? In reality, things are not that easy. Various factors contribute to making this API much trickier than it might seem at first glance. This post explains the fundamental underpinnings of the keychain. For information about specific issues, see its companion post, SecItem: Pitfalls and Best Practices. Keychain Documentation Your basic starting point should be Keychain Items. If your code runs on the Mac, also read TN3137 On Mac keychain APIs and implementations. Read the doc comments in <Security/SecItem.h>. In many cases those doc comments contain critical tidbits. When you read keychain documentation [1] and doc comments, keep in mind that statements specific to iOS typically apply to iPadOS, tvOS, and watchOS as well (r. 102786959). Also, they typically apply to macOS when you target the data protection keychain. Conversely, statements specific to macOS may not apply when you target the data protection keychain. [1] Except TN3137, which is very clear about this (-: Caveat Mac Developer macOS supports two different keychain implementations: the original file-based keychain and the iOS-style data protection keychain. IMPORTANT If you’re able to use the data protection keychain, do so. It’ll make your life easier. See the Careful With that Shim, Mac Developer section of SecItem: Pitfalls and Best Practices for more about this. TN3137 On Mac keychain APIs and implementations explains this distinction. It also says: The file-based keychain is on the road to deprecation. This is talking about the implementation, not any specific API. The SecItem API can’t be deprecated because it works with both the data protection keychain and the file-based keychain. However, Apple has deprecated many APIs that are specific to the file-based keychain, for example, SecKeychainCreate. TN3137 also notes that some programs, like launchd daemons, can’t use the file-based keychain. If you’re working on such a program then you don’t have to worry about the deprecation of these file-based keychain APIs. You’re already stuck with the file-based keychain implementation, so using a deprecated file-based keychain API doesn’t make things worse. The Four Freedoms^H^H^H^H^H^H^H^H Functions The SecItem API contains just four functions: SecItemAdd(_:_:) SecItemCopyMatching(_:_:) SecItemUpdate(_:_:) SecItemDelete(_:) These directly map to standard SQL database operations: SecItemAdd(_:_:) maps to INSERT. SecItemCopyMatching(_:_:) maps to SELECT. SecItemUpdate(_:_:) maps to UPDATE. SecItemDelete(_:) maps to DELETE. You can think of each keychain item class (generic password, certificate, and so on) as a separate SQL table within the database. The rows of that table are the individual keychain items for that class and the columns are the attributes of those items. Note Except for the digital identity class, kSecClassIdentity, where the values are split across the certificate and key tables. See Digital Identities Aren’t Real in SecItem: Pitfalls and Best Practices. This is not an accident. The data protection keychain is actually implemented as an SQLite database. If you’re curious about its structure, examine it on the Mac by pointing your favourite SQLite inspection tool — for example, the sqlite3 command-line tool — at the keychain database in ~/Library/Keychains/UUU/keychain-2.db, where UUU is a UUID. WARNING Do not depend on the location and structure of this file. These have changed in the past and are likely to change again in the future. If you embed knowledge of them into a shipping product, it’s likely that your product will have binary compatibility problems at some point in the future. The only reason I’m mentioning them here is because I find it helpful to poke around in the file to get a better understanding of how the API works. For information about which attributes are supported by each keychain item class — that is, what columns are in each table — see the Note box at the top of Item Attribute Keys and Values. Alternatively, look at the Attribute Key Constants doc comment in <Security/SecItem.h>. Uniqueness A critical part of the keychain model is uniqueness. How does the keychain determine if item A is the same as item B? It turns out that this is class dependent. For each keychain item class there is a set of attributes that form the uniqueness constraint for items of that class. That is, if you try to add item A where all of its attributes are the same as item B, the add fails with errSecDuplicateItem. For more information, see the errSecDuplicateItem page. It has lists of attributes that make up this uniqueness constraint, one for each class. These uniqueness constraints are a major source of confusion, as discussed in the Queries and the Uniqueness Constraints section of SecItem: Pitfalls and Best Practices. Parameter Blocks Understanding The SecItem API is a classic ‘parameter block’ API. All of its inputs are dictionaries, and you have to know which properties to set in each dictionary to achieve your desired result. Likewise for when you read properties in output dictionaries. There are five different property groups: The item class property, kSecClass, determines the class of item you’re operating on: kSecClassGenericPassword, kSecClassCertificate, and so on. The item attribute properties, like kSecAttrAccessGroup, map directly to keychain item attributes. The search properties, like kSecMatchLimit, control how the system runs a query. The return type properties, like kSecReturnAttributes, determine what values the query returns. The value type properties, like kSecValueRef perform multiple duties, as explained below. There are other properties that perform a variety of specific functions. For example, kSecUseDataProtectionKeychain tells macOS to use the data protection keychain instead of the file-based keychain. These properties are hard to describe in general; for the details, see the documentation for each such property. Inputs Each of the four SecItem functions take dictionary input parameters of the same type, CFDictionary, but these dictionaries are not the same. Different dictionaries support different property groups: The first parameter of SecItemAdd(_:_:) is an add dictionary. It supports all property groups except the search properties. The first parameter of SecItemCopyMatching(_:_:) is a query and return dictionary. It supports all property groups. The first parameter of SecItemUpdate(_:_:) is a pure query dictionary. It supports all property groups except the return type properties. Likewise for the only parameter of SecItemDelete(_:). The second parameter of SecItemUpdate(_:_:) is an update dictionary. It supports the item attribute and value type property groups. Outputs Two of the SecItem functions, SecItemAdd(_:_:) and SecItemCopyMatching(_:_:), return values. These output parameters are of type CFTypeRef because the type of value you get back depends on the return type properties you supply in the input dictionary: If you supply a single return type property, except kSecReturnAttributes, you get back a value appropriate for that return type. If you supply multiple return type properties or kSecReturnAttributes, you get back a dictionary. This supports the item attribute and value type property groups. To get a non-attribute value from this dictionary, use the value type property that corresponds to its return type property. For example, if you set kSecReturnPersistentRef in the input dictionary, use kSecValuePersistentRef to get the persistent reference from the output dictionary. In the single item case, the type of value you get back depends on the return type property and the keychain item class: For kSecReturnData you get back the keychain item’s data. This makes most sense for password items, where the data holds the password. It also works for certificate items, where you get back the DER-encoded certificate. Using this for key items is kinda sketchy. If you want to export a key, called SecKeyCopyExternalRepresentation. Using this for digital identity items is nonsensical. For kSecReturnRef you get back an object reference. This only works for keychain item classes that have an object representation, namely certificates, keys, and digital identities. You get back a SecCertificate, a SecKey, or a SecIdentity, respectively. For kSecReturnPersistentRef you get back a data value that holds the persistent reference. Value Type Subtleties There are three properties in the value type property group: kSecValueData kSecValueRef kSecValuePersistentRef Their semantics vary based on the dictionary type. For kSecValueData: In an add dictionary, this is the value of the item to add. For example, when adding a generic password item (kSecClassGenericPassword), the value of this key is a Data value containing the password. This is not supported in a query dictionary. In an update dictionary, this is the new value for the item. For kSecValueRef: In add and query dictionaries, the system infers the class property and attribute properties from the supplied object. For example, if you supply a certificate object (SecCertificate, created using SecCertificateCreateWithData), the system will infer a kSecClass value of kSecClassCertificate and various attribute values, like kSecAttrSerialNumber, from that certificate object. This is not supported in an update dictionary. For kSecValuePersistentRef: For query dictionaries, this uniquely identifies the item to operate on. This is not supported in add and update dictionaries. Revision History 2025-05-28 Expanded the Caveat Mac Developer section to cover some subtleties associated with the deprecation of the file-based keychain. 2023-09-12 Fixed various bugs in the revision history. Added a paragraph explaining how to determine which attributes are supported by each keychain item class. 2023-02-22 Made minor editorial changes. 2023-01-28 First posted.
Replies
0
Boosts
0
Views
4.4k
Activity
May ’25
DeviceCheck - Device Validation Endpoint not working
We have been having very high response times in device check device validation service (https://developer.apple.com/documentation/devicecheck/accessing-and-modifying-per-device-data#Create-the-payload-for-a-device-validation-request) since 17 July at 19:10hs GMT. The service information page says the service was running in green status but that isn't the case and we currenly have stop consuming it. Is it being looked at? Are you aware of this issue? Can you give us an estimate of when it should be working correctly?
Replies
1
Boosts
0
Views
807
Activity
Jul ’25
Problem Saving a ASPasskeyCredentialIdentity
Hi I'm developing an app that autofills Passkeys. The app allows the user to authenticate to their IdP to obtain an access token. Using the token the app fetches from <server>/attestation/options. The app will generate a Passkey credential using a home-grown module - the extension has no involvement, neither does ASAuthorizationSecurityKeyPublicKeyCredentialProvider. I can confirm the passkey does get created. Next the credential is posted to <server>/attestation/results with the response JSON being parsed and used to create a ASPasskeyCredentialIdentity - a sample of the response JSON is attached. Here is my save function: static func save(authenticator: AuthenticatorInfo) async throws { guard let credentialID = Data(base64URLEncoded: authenticator.attributes.credentialId) else { throw AuthenticatorError.invalidEncoding("Credential ID is not a valid Base64URL string.") } guard let userHandle = authenticator.userId.data(using: .utf8) else { throw AuthenticatorError.invalidEncoding("User handle is not a valid UTF-8 string.") } let identity = ASPasskeyCredentialIdentity( relyingPartyIdentifier: authenticator.attributes.rpId, userName: authenticator.userId, // This is what the user sees in the UI credentialID: credentialID, userHandle: userHandle, recordIdentifier: authenticator.id ) try await ASCredentialIdentityStore.shared.saveCredentialIdentities([identity]) } Although no error occurs, I don't get any identities returned when I call this method: let identities = await ASCredentialIdentityStore.shared.credentialIdentities( forService: nil, credentialIdentityTypes: [.passkey] ) Here is the Info.plist in the Extension: <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>ASCredentialProviderExtensionCapabilities</key> <dict> <key>ProvidesPasskeys</key> <true/> </dict> <key>ASCredentialProviderExtensionShowsConfigurationUI</key> <true/> </dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.authentication-services-credential-provider-ui</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).CredentialProviderViewController</string> </dict> </dict> </plist> The entitlements are valid and the app and extension both support the same group. I'm stumped as to why the identity is not getting saved. Any ideas and not getting retrieved. attestationResult.json
Replies
1
Boosts
0
Views
428
Activity
Jan ’26
AASA not being fetched immediately upon app install
Hi Apple Devs, For our app, we utilize passkeys for account creation (not MFA). This is mainly for user privacy, as there is 0 PII associated with passkey account creation, but it additionally also satisfies the 4.8: Login Services requirement for the App Store. However, we're getting blocked in Apple Review. Because the AASA does not get fetched immediately upon app install, the reviewers are not able to create an account immediately via passkeys, and then they reject the build. I'm optimistic I can mitigate the above. But even if we pass Apple Review, this is a pretty catastrophic issue for user security and experience. There are reports that 5% of users cannot create passkeys immediately (https://developer.apple.com/forums/thread/756740). That is a nontrivial amount of users, and this large of an amount distorts how app developers design onboarding and authentication flows towards less secure experiences: App developers are incentivized to not require MFA setup on account creation because requiring it causes significant churn, which is bad for user security. If they continue with it anyways, for mitigation, developers are essentially forced to add in copy into their app saying something along the lines of "We have no ability to force Apple to fetch the config required to continue sign up, so try again in a few minutes, you'll just have to wait." You can't even implement a fallback method. There's no way to check if the AASA is available before launching the ASAuthorizationController so you can't mitigate a portion of users encountering an error!! Any app that wants to use the PRF extension to encrypt core functionality (again, good for user privacy) simply cannot exist because the app simply does not work for an unspecified amount of time for a nontrivial portion of users. It feels like a. Apple should provide a syscall API that we can call to force SWCD to verify the AASA or b. implement a config based on package name for the app store such that the installation will immediately include a verified AASA from Apple's CDN. Flicking the config on would require talking with Apple. If this existed, this entire class of error would go away. It feels pretty shocking that there isn't a mitigation in place for this already given that it incentivizes app developers to pursue strictly less secure and less private authentication practices.
Replies
0
Boosts
0
Views
392
Activity
Aug ’25
App transfer- get transfer {"error":"invalid_request"}
Migrating APP and users, obtaining the user's transfer_sub, an exception occurred: {"error":"invalid_request"} `POST /auth/usermigrationinfo HTTP/1.1 Host: appleid.apple.com Content-Type: application/x-www-form-urlencoded Authorization: Bearer {access_token} sub={sub}&target={recipient_team_id}&client_id={client_id}&client_secret={client_secret} The specific request is as follows: 15:56:20.858 AppleService - --> POST https://appleid.apple.com/auth/usermigrationinfo 15:56:20.858 AppleService - Content-Type: application/x-www-form-urlencoded 15:56:20.858 AppleService - Content-Length: 395 15:56:20.858 AppleService - Authorization: Bearer a56a8828048af48c0871e73b55d8910aa.0.rzvs.96uUcy1KBqo34Kj8qrPb4w 15:56:20.858 AppleService - 15:56:20.858 AppleService - sub=001315.1535dbadc15b472987acdf634719a06a.0600&target=WLN67KBBV8&client_id=com.hawatalk.live&client_secret=eyJraWQiOiIzODg5U1ZXNDM5IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJRMzlUU1BHMjk3IiwiaWF0IjoxNzU1MDcxNzc5LCJleHAiOjE3NTUwNzUzNzksImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJzdWIiOiJjb20uaGF3YXRhbGsubGl2ZSJ9.8i9RYIcepuIiEqOMu1OOAlmmjnB84AJueel21gNapiNa9pr3498Zkj8J5MUIzvvnvsvUJkKQjp_VvnsG_IIrTA 15:56:20.859 AppleService - --> END POST (395-byte body) 15:56:21.675 AppleService - <-- 400 Bad Request https://appleid.apple.com/auth/usermigrationinfo(816ms) 15:56:21.675 AppleService - Server: Apple 15:56:21.675 AppleService - Date: Wed, 13 Aug 2025 07:56:22 GMT 15:56:21.675 AppleService - Content-Type: application/json;charset=UTF-8 15:56:21.675 AppleService - Content-Length: 27 15:56:21.675 AppleService - Connection: keep-alive 15:56:21.675 AppleService - Pragma: no-cache 15:56:21.675 AppleService - Cache-Control: no-store 15:56:21.676 AppleService - 15:56:21.676 AppleService - {"error":"invalid_request"} 15:56:21.676 AppleService - <-- END HTTP (27-byte body) ` Current Team ID: Q39TSPG297 Recipient Team ID: WLN67KBBV8 CLIENT_ID: com.hawatalk.live
Replies
0
Boosts
0
Views
192
Activity
Aug ’25
In which cases, ASCredentialIdentityStore returns false supportsIncrementalUpdates?
I want to use incrementalUpdates for my app but store always returns false on my iPad with OS18.3.2. I want to know what are th conditions in which store says its unable to perform incrementalUpdates?
Replies
0
Boosts
0
Views
63
Activity
Apr ’25
Sudden Increase of Hard Bounce with privaterelay emails
We have been sending emails through Sparkpost via Braze inc. to the Apple Private Relay users with "@privaterelay.appleid.com" starting from around June 20th or so. Upon August 9th 06:00 UTC, we have noticed a sudden increase of "Hard Bounce" for nearly 20,000 users using the Apple's private relay email address, rendering the email sending useless for these customers. We have been constantly been able to send them emails, including just before this timeframe (e.g. August 9th 03:00 UTC), so it was a very sudden purge of the user data that has been done without our consent. From a business perspective, this hurts a lot for the un-sendable users since we have no way of contacting them if not for the private address. We are desperate to know what has happened for these customers that has been "hard bounced". We are suspecting that it should be tied to the private email and the users primary email (or user data's) tie in the Apple server being gone, but not sure enough since there is no such documentation nor any way to acknowledge what has happened anywhere. We will provide any information possible for resolving. Thank you.
Replies
0
Boosts
0
Views
326
Activity
Aug ’25
Mac App Store app triggers "cannot verify free of malware" alert when opening as default app
My app Mocawave is a music player distributed through the Mac App Store. It declares specific audio document types (public.mp3, com.microsoft.waveform-audio, public.mpeg-4-audio, public.aac-audio) in its CFBundleDocumentTypes with a Viewer role. When a user sets Mocawave as the default app for audio files and double-clicks an MP3 downloaded from the internet (which has the com.apple.quarantine extended attribute), macOS displays the alert: "Apple could not verify [filename] is free of malware that may harm your Mac or compromise your privacy." This does not happen when: Opening the same file via NSOpenPanel from within the app Opening the same file with Apple's Music.app or QuickTime Player The app is: Distributed through the Mac App Store Sandboxed (com.apple.security.app-sandbox) Uses com.apple.security.files.user-selected.read-write entitlement The file being opened is a regular audio file (MP3), not an executable. Since the app is sandboxed and distributed through the App Store, I expected it to have sufficient trust to open quarantined data files without triggering Gatekeeper warnings — similar to how Music.app and QuickTime handle them. Questions: Is there a specific entitlement or Info.plist configuration that allows a sandboxed Mac App Store app to open quarantined audio files without this alert? Is this expected behavior for third-party App Store apps, or could this indicate a misconfiguration on my end? Environment: macOS 15 (Sequoia), app built with Swift/SwiftUI, targeting macOS 13+.
Replies
2
Boosts
0
Views
188
Activity
Feb ’26
Fraud prevention using Device Check when publishing multiple apps
I would like to confirm about fraud prevention using Device Check when publishing multiple apps. If the Team ID and Key ID are the same, will the values be shared across all apps with Device Check? With Device Check, only two keys can be created per developer account, and these two are primarily intended for key renewal in case of a leak, rather than for assigning different keys to each app, correct? If both 1 and 2 are correct, does that mean that Device Check should not be used to manage "one-time-only rewards per device" when offering them across multiple apps? Thank you very much for your confirmation.
Replies
0
Boosts
0
Views
211
Activity
Apr ’25
Apple SignIn configuration change from Group to Primary ID
I have two applications, and I recently decided to add the Apple Sign In feature. Initially, I configured it for one of the apps as the Primary ID for this feature. Everything worked well, and I decided to add it to the second app. I made a mistake and used the First app as Primary ID using the "Group with an existing primary App ID" flag. Now, when I sign in using the second app, I don't see it in the list of apps in iPhone Settings for Apple Sign In; I only see the primary app. And with that, I no longer see a prompt for sharing/hiding email, and I am unable to revoke credentials correctly. I decided to change the Second app's Sign-in config and set it as the Primary ID for the feature. I was hoping to get two apps independent for the SignIn. However, it doesn't seem to make a difference. The second app behaves the same way, as long as the first app used SignIn, the second one always thinks that the user has already used that feature and never shows the correct prompt. Is there something I missed after changing the Configuration?
Replies
0
Boosts
0
Views
172
Activity
Jul ’25
iPad App Suggestions - Api Security
Hi , I have a requirement like, Develop an app for iPad and app uses .net core apis. App will be in kiosk mode, and app doesn't have any type of authentication even OTP also. As the apis will be publishing to all over internet, how can we achieve security to apis? Kindly provide suggestions for this implementation
Replies
1
Boosts
0
Views
223
Activity
Sep ’25
Authentication using MSAL library in offline mode
Hi. We are trying to get the access token before calling any API. The app can go in bad network areas but the token acquisition keeps happening for the network call. The devices are managed devices which means it has some policies installed. We are using MSAL lib for the authentication and we are investigating from that angle too but the below error seems to be coming from apple authentication which needs our attention. ========================================== LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=68, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} Attempt to map database failed: permission was denied. This attempt will not be retried. Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=68, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} Failed to get application extension record: Error Domain=NSOSStatusErrorDomain Code=-54 "(null)" ASAuthorizationController credential request failed with error: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1003 "(null)" ========================================== This happens mostly when we switches the network or keep the device in no or low network area. This comes sometimes when app goes in background too. Just trying to give as much as information I could. Any lead would be highly appreciated. Thank you
Replies
0
Boosts
0
Views
139
Activity
Apr ’25
App Attest attestationData request fails with 400 Bad Request (no X-Request-ID)
Hello Apple Team We are integrating App Attest with our backend and seeing a 400 Bad Request response when calling the attestation endpoint. The issue is that the response does not include an X-Request-ID or JSON error payload with id and code, which makes it hard to diagnose. Instead, it only returns a receipt blob. Request Details URL: https://data-development.appattest.apple.com/v1/attestationData Request Headers: Authorization: eyJraWQiOiI0RjVLSzRGV1JaIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJOOVNVR1pNNjdRIiwiZXhwIjoxNzU3MDUxNTYwLCJpYXQiOjE3NTcwNDc5NjB9.MEQCIF236MqPCl6Vexg7RcPUMK8XQeACXogldnpuiNnGQnzgAiBQqASdbJ64g58xfWGpbzY3iohvxBSO5U5ZE3l87JjfmQ Content-Type: application/octet-stream Request Body: (Binary data, logged as [B@59fd7d35) Response Status: 400 Bad Request Response Headers: Date: Fri, 05 Sep 2025 04:52:40 GMT x-b3-traceid: 4c42e18094022424 x-b3-spanid: 4c42e18094022424 Response Body (truncated): "receipt": h'308006092A864886F70D01070... Problem The response does not include X-Request-ID. The response does not include JSON with id or code. Only a receipt blob is returned. Questions Can the x-b3-traceid be used by Apple to trace this failed request internally? Is it expected for some failures to return only a receipt blob without X-Request-ID? How should we interpret this error so we can handle it properly in production? Thanks in advance for your guidance.
Replies
1
Boosts
0
Views
511
Activity
Sep ’25
Critical Privacy and Security Issue: Spotlight disregards explicit exclusions and exposes user files
Apple has repeatedly ignored my reports about a critical privacy issue in Spotlight on macOS 26, and the problem persists in version 26.3 RC. This is not a minor glitch, it is a fundamental breach of user trust and privacy. Several aspects of Spotlight fail to respect user settings: • Hidden apps still exposed: In the Apps section (Cmd+1), Spotlight continues to display apps marked with the hidden flag, even though they should remain invisible. • Clipboard reactivation: The clipboard feature repeatedly turns itself back on after logout or restart, despite being explicitly disabled by the user. • Excluded files revealed: Most concerning, Spotlight exposes files in Suggestions and Recents (Cmd+3) even when those files are explicitly excluded under System Settings > Spotlight > Search Privacy. This behavior directly violates user expectations and system settings. It is not only a major privacy issue but also a security risk, since sensitive files can be surfaced without consent. Apple must address this immediately. Users rely on Spotlight to respect their privacy configurations, and the current behavior undermines both trust and security.
Replies
2
Boosts
0
Views
485
Activity
Feb ’26
Implementing Script Attachment in a Sandboxed App
Script attachment enables advanced users to create powerful workflows that start in your app. NSUserScriptTask lets you implement script attachment even if your app is sandboxed. This post explains how to set that up. IMPORTANT Most sandboxed apps are sandboxed because they ship on the Mac App Store [1]. While I don’t work for App Review, and thus can’t make definitive statements on their behalf, I want to be clear that NSUserScriptTask is intended to be used to implement script attachment, not as a general-purpose sandbox bypass mechanism. If you have questions or comments, please put them in a new thread. Place it in the Privacy &amp; Security &gt; General subtopic, and tag it with App Sandbox. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] Most but not all. There are good reasons to sandbox your app even if you distribute it directly. See The Case for Sandboxing a Directly Distributed App. Implementing Script Attachment in a Sandboxed App Some apps support script attachment, that is, they allow a user to configure the app to run a script when a particular event occurs. For example: A productivity app might let a user automate repetitive tasks by configuring a toolbar button to run a script. A mail client might let a user add a script that processes incoming mail. When adding script attachment to your app, consider whether your scripting mechanism is internal or external: An internal script is one that only affects the state of the app. A user script is one that operates as the user, that is, it can change the state of other apps or the system as a whole. Supporting user scripts in a sandboxed app is a conundrum. The App Sandbox prevents your app from changing the state of other apps, but that’s exactly what your app needs to do to support user scripts. NSUserScriptTask resolves this conundrum. Use it to run scripts that the user has placed in your app’s Script folder. Because these scripts were specifically installed by the user, their presence indicates user intent and the system runs them outside of your app’s sandbox. Provide easy access to your app’s Script folder Your application’s Scripts folder is hidden within ~/Library. To make it easier for the user to add scripts, add a button or menu item that uses NSWorkspace to show it in the Finder: let scriptsDir = try FileManager.default.url(for: .applicationScriptsDirectory, in: .userDomainMask, appropriateFor: nil, create: true) NSWorkspace.shared.activateFileViewerSelecting([scriptsDir]) Enumerate the available scripts To show a list of scripts to the user, enumerate the Scripts folder: let scriptsDir = try FileManager.default.url(for: .applicationScriptsDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let scriptURLs = try FileManager.default.contentsOfDirectory(at: scriptsDir, includingPropertiesForKeys: [.localizedNameKey]) let scriptNames = try scriptURLs.map { url in return try url.resourceValues(forKeys: [.localizedNameKey]).localizedName! } This uses .localizedNameKey to get the name to display to the user. This takes care of various edge cases, for example, it removes the file name extension if it’s hidden. Run a script To run a script, instantiate an NSUserScriptTask object and call its execute() method: let script = try NSUserScriptTask(url: url) try await script.execute() Run a script with arguments NSUserScriptTask has three subclasses that support additional functionality depending on the type of the script. Use the NSUserUnixTask subsclass to run a Unix script and: Supply command-line arguments. Connect pipes to stdin, stdout, and stderr. Get the termination status. Use the NSUserAppleScriptTask subclass to run an AppleScript, executing either the run handler or a custom Apple event. Use the NSUserAutomatorTask subclass to run an Automator workflow, supplying an optional input. To determine what type of script you have, try casting it to each of the subclasses: let script: NSUserScriptTask = … switch script { case let script as NSUserUnixTask: … use Unix-specific functionality … case let script as NSUserAppleScriptTask: … use AppleScript-specific functionality … case let script as NSUserAutomatorTask: … use Automatic-specific functionality … default: … use generic functionality … }
Replies
0
Boosts
0
Views
988
Activity
Aug ’25