The build uploaded fine, but a few minutes later App Store Connect sent the ITMS-91053 email naming NSPrivacyAccessedAPICategoryFileTimestamp and the binary moved into the Invalid Binary state. The fix is almost always a small edit to PrivacyInfo.xcprivacy, not a code change.
Short answer
ITMS-91053 fires when the App Store Connect static scanner finds a call into Apple's required-reason API set for file timestamps (stat, fstat, modificationDate, creationDate, NSURLContentModificationDateKey, std::filesystem helpers) and the build has no privacy manifest entry that names an approved reason. The fix is to add a PrivacyInfo.xcprivacy file (or extend the existing one), declare NSPrivacyAccessedAPICategoryFileTimestamp, and list one of the four approved reason codes that matches what the binary actually does.
What you should know
- The deadline is settled. Since May 1, 2024, Apple has blocked uploads that touch required-reason APIs without a privacy manifest declaration covering each category.
- file_timestamp is one of five required-reason categories. The others are disk_space, system_boot_time, active_keyboard, and user_defaults; each carries its own closed list of approved reasons.
- Four reason codes exist for file_timestamp. DDA9.1, C617.1, 3B52.1, and 0A2A.1. They are not interchangeable, and the choice depends on the file's location.
- The scanner runs on the IPA, not the source. Stripping a call from a Swift file changes nothing if the compiled binary still links the symbol from a vendored library.
- Third-party SDKs need their own privacy manifest. A first-party app manifest does not satisfy ITMS-91053 when the file_timestamp call originates inside a vendored framework.
What does the ITMS-91053 email about file_timestamp mean?
The short answer is that Apple's automated review system scanned the .ipa, found a call into a category Apple considers a fingerprinting risk, and could not match it to an approved reason in the privacy manifest.
Per Apple's required-reason API documentation, each of the five required-reason categories carries a closed list of acceptable reasons. file_timestamp APIs are flagged because reading file metadata (creation date, modification date, byte count) can be combined into a stable signal that survives reinstalls and identifies the device. The ITMS-91053 email names the category and tells you the upload is now in Invalid Binary state; the build still appears in App Store Connect, but it cannot be assigned to TestFlight or sent for review until a corrected version arrives.
The most common pattern in practice is a single missing entry on an otherwise correct PrivacyInfo.xcprivacy, not a missing manifest entirely. The scanner runs after every upload, including bug-fix releases of long-shipping apps, so an app that has cleared the gate in the past can still trip ITMS-91053 on a release that adds a new required-reason API call.
Which APIs in my code count as file_timestamp access?
The short answer is anything that ultimately calls stat(2) or one of its variants, plus the high-level Foundation accessors that wrap them.
The functions that count under NSPrivacyAccessedAPICategoryFileTimestamp include:
- creationDate and modificationDate on URLResourceValues
- NSURLContentModificationDateKey, NSURLCreationDateKey, NSURLAttributeModificationDateKey, NSURLContentAccessDateKey
- FileManager.attributesOfItem(atPath:) when reading the .modificationDate or .creationDate keys
- POSIX stat(), fstat(), lstat(), fstatat()
- C++ std::filesystem::last_write_time and any std::filesystem helper that internally invokes stat
The Apple Developer Forums thread on stat() as a Required Reason API clarified in December 2023 that the C++ filesystem helpers count even though they are not named on the documentation list. In practice the static scanner inspects the symbol table of the binary, so any object file that links one of these symbols triggers the flag, regardless of whether the call is ever reached at runtime. Dead code paths in vendored static libraries are a common surprise.
Which reason code should I declare in PrivacyInfo.xcprivacy?
The short answer is whichever reason matches the file the code touches, not what the function name says.
Apple defines four approved reasons for file_timestamp. The right pick depends on which directory the file lives in and whether the timestamp ever leaves the device.
| Reason code | When to declare it | Off-device share allowed? |
|---|---|---|
| C617.1 | Reading timestamps, size, or metadata of files inside the app container, app group container, or the app's CloudKit container | Yes, within the app's normal data flow |
| 3B52.1 | Reading timestamps of files the user explicitly granted access to (document picker, share extension target) | Yes, within the app's normal data flow |
| DDA9.1 | Displaying a file's timestamp to the person using the device | No; the information may not be sent off-device |
| 0A2A.1 | Third-party SDKs wrapping file timestamp APIs for host apps to call | No; the SDK may not use the data for its own purposes or send it off-device |
Most first-party apps end up with C617.1 alone. An app that also imports files from the Files app or a share extension adds 3B52.1. An app whose only timestamp use is a "Last updated 3 minutes ago" label on a UI cell can declare DDA9.1, but the off-device restriction then applies to that data path, which rules out forwarding the timestamp to analytics.
How do I add the NSPrivacyAccessedAPITypes entry in Xcode?
The short answer is one file (PrivacyInfo.xcprivacy) at the root of the target's bundle resources, with a property-list dictionary that names the category and its reasons.
In Xcode, choose File, New, File from Template, App Privacy. Save as PrivacyInfo.xcprivacy and add it to the target that ships the affected code. The minimum content for a file_timestamp fix looks like this:
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPIReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
Each required-reason category the binary touches gets its own dictionary inside NSPrivacyAccessedAPITypes. The file lives at the resource root of the .app bundle for first-party code or inside the .framework / .xcframework for an SDK, per Apple's privacy manifest files reference. A new Archive, a fresh upload to App Store Connect, and the binary clears ITMS-91053 within a few minutes if no other categories are missing.
What if the call comes from a third-party SDK?
The short answer is the SDK has to ship its own PrivacyInfo.xcprivacy, and on the published list it has to ship one that is cryptographically signed.
The app's own manifest covers only first-party code. When the scanner finds a file_timestamp symbol inside a vendored .framework or Swift package, the rejection still cites the app, but the resolution lives in the SDK. Two cases follow.
The SDK is on Apple's list of commonly used third-party SDKs that need signed privacy manifests (Firebase, Google Mobile Ads, Adjust, Amplitude, and many more). Apple expected a signed manifest inside the framework for new uploads from February 2024 and for all uploads from May 2024. Updating to the SDK version that includes the signed manifest is the fix; nothing in the host app's PrivacyInfo.xcprivacy substitutes for the SDK's own file.
The SDK is not on the published list. The SDK still needs a privacy manifest if it calls a required-reason API, but the signature is not required. Filing a ticket with the SDK vendor (or vendoring a patched copy that ships the manifest) is the typical path. Tools that compare the declared categories in the manifest against the symbols actually present in the binary are useful here. For builders who want an external read of which categories are declared, which are missing, and which originate inside a vendored SDK before the next App Store Connect upload, PTKD.com (https://ptkd.com) is one of the platforms that scans the compiled IPA against the OWASP MASVS data storage controls and lists the privacy manifest entries the binary appears to need.
What to watch out for
The first trap is treating ITMS-91053 as a code bug. The static scanner reports symbol presence, not call reachability. Dead code that links a stat symbol still trips the email; the fix is the declaration, not removing the call.
The second trap is declaring DDA9.1 to be safe across the board. DDA9.1 forbids sending the timestamp off the device, including inside analytics events or server-side logs. If the app's analytics SDK forwards a "file last modified" property anywhere, DDA9.1 is the wrong code, and the correct one (C617.1 in most cases) is needed.
The third trap is editing the SDK's PrivacyInfo.xcprivacy by hand. SDKs on the published list ship a signed manifest; manually editing the file inside the framework breaks the signature, and either the SDK's own runtime checks fail or App Store Connect reports the framework as tampered with on the next upload. The fix is to upgrade the SDK, not to patch its manifest.
The fourth trap is assuming a clean ITMS-91053 means a clean required-reason audit forever. The scanner reports the categories it finds in the upload event you just sent. Adding a Foundation call to a future release that touches user_defaults or disk_space starts a new rejection cycle. Reviewing the privacy manifest as part of the release diff, not as a one-time setup, keeps the next submission boring.
Key takeaways
- ITMS-91053 with NSPrivacyAccessedAPICategoryFileTimestamp is almost always a missing or under-declared PrivacyInfo.xcprivacy entry; code changes are rarely required.
- Pick the reason code that matches the directory the file lives in: C617.1 for app container files, 3B52.1 for user-granted files, DDA9.1 for on-device display only, 0A2A.1 only inside a third-party SDK wrapper.
- When the call originates inside a vendored framework, the fix moves into the SDK: either upgrade to a version that ships a signed privacy manifest, or coordinate with the vendor for a release that does.
- Treat the privacy manifest as part of every release diff; the scanner inspects every new upload, including bug-fix versions of long-shipping apps, and a new required-reason API in the codebase restarts the rejection cycle.
- Some teams outsource the verification step to platforms like PTKD.com (https://ptkd.com), which scan the compiled IPA, list the required-reason categories the symbols actually trigger, and check the privacy manifest declarations against the OWASP MASVS data storage controls before the next App Store Connect upload.



