AirTrafficDevice: Ignored, Reluctantly Fixed, No CVE, No Bounty: A Story of a Serious Privacy Leak in iOS.
/Preamble
First, I’d like to state that I am incredibly grateful to all the people who have helped me in the past. However, October hasn’t been too kind to me. I was trying to get a job, but that fell through. I’m currently overdrawn, can’t afford the sadly expensive rent (and don’t have enough money to move to a cheaper location than Silicon Valley), I’m a month behind on my electricity bill, and I’ll lose all health insurance if I can’t pay October’s bill by October 30th. I’m also so overdrawn on my accounts that I can neither afford groceries nor can I afford the appointments needed to manage my disability.
I’ve set up a GoFundMe and would appreciate any and all help! There is far more information on my situation there. Also, please make sure to check my CV as I’m actively looking for steady work.
My Personal Goals and Impetus
I care about user privacy, possibly to an unhealthy degree. Since May this year, I’ve been developing an iOS app to largely automate the discovery of privacy flaws, including data that Apple forgot that can leak personal information or expose unique identifiers. These leaks allow the bad guys (malware vendors, Facebook, unscrupulous ad companies, and so forth) to track users across apps and devices.
That lets them target us with malware, sell our data to the highest bidder for targeted ads (violating the spirit of App Tracking Transparency), or build detailed user profiles by aggregating data from various sources, known as Shadow Profiles. Even worse, some leaks reveal information that, in certain jurisdictions, could lead to arresting or disappearing users, like leaking what apps you have installed. I’ve found several of those...
I wholly and utterly believe in the principle behind Apple’s App Tracking Transparency initiative. I therefore consider anything that is both
uniquely tied to a user and
available when “Allow Apps to Request to Track” is disabled to be a gross violation of the spirit of App Tracking Transparency.
Because Apple has a security/privacy bug bounty, I figured I could attack two problems with one action:
I could make iOS devices safer for users.
I could potentially turn it into an income source.
Sadly, the latter hasn’t happened. While Apple has fixed 3-4 (search for my name) of the 21 privacy bugs (and one kernel panic) I reported, Apple decided they weren’t eligible for the bug bounty. One (CVE-2025-43357) wasn’t eligible because I wasn’t the first to report it to Apple, which makes sense. I understand why the AuthKit bug wasn’t eligible for a bounty, even though it leaked fingerprintable information; it was more of a persistent annoyance to me and prevented me from discovering other privacy leaks in iOS due to the noise from AuthKit.
Fortunately, a future release of iOS 26.x will address a privacy leak I reported, which qualifies for the lowest bounty. Unfortunately, Apple won’t pay the bounty until several weeks after the fix is publicly released, so I won’t be able to use it to cover my October bills.
The Meat of This Post
I’m planning to follow Google Project Zero’s “Responsible Disclosure” process for this privacy leak. The bug was publicly fixed in iOS 26 et fam and was silently fixed in 18.7. Although it’s not mentioned anywhere in the iOS 18.7 release notes, I can no longer reproduce it on an iOS device running iOS 18.7, despite repeated efforts.
Today, I’m discussing a privacy leak reported to Apple as OE11020806152810 on 2025-05-20, and when I realized it also leaked DSIDs (Directory Service Identifiers), I created a new report (OE1102442124011).
Apple only needed to implement one change to fix both reports, which Apple listed as:
“Sandbox Profiles
We would like to acknowledge Rosyna Keller of Totally Not Malicious Software for their assistance.”
When I first reported OE11020806152810, it was almost immediately closed as “Not to be fixed”. I had to gently poke a few bears to get it back to “we’ll fix this.”
However, Apple never assigned a CVE while reluctantly fixing this serious bug/privacy leak.
The AirTrafficDevice framework on iOS is responsible for syncing information between an iOS device and the Finder, iTunes, or the Windows Apple Devices app (depending on your Mac vs. PC choices). It stores the following information on the iOS device:
- All DSIDs that are required to play media and use downloaded apps on the iOS device. Every Apple ID has an immutable DSID associated with it. That’s “immutable” as in it never changes, even if you change your Apple ID login information. Bad people can use it to track users across apps and devices. If you have different Apple IDs, say one for iCloud and a different one for app purchases, AirTrafficDevice stores both. If you ever bought protected music in Japan via a Japanese iTunes Music Store gift card (back when the Japanese iTMS had DRM on all songs, something strangely common in my friend group), AirTrafficDevice stores that DSID also. Due to their global uniqueness, I consider DSIDs to be the Holy Grail of Tracking Users.
[[ATUserDefaults sharedInstance] allHosts]returns a dictionary of globally unique identifiers representing each Mac and/or Windows PC as keys. They look like UUIDs without dashes.- Each host dictionary contains a value called
SyncHostName, which holds the name of the Mac (as set in System Settings > General > About > Name on macOS) or PC. Your computer name may be globally unique if you chose your own. If not, then on macOS, it defaults to containing your first name. For example, if I change my computer’s name to “Puri-Puri PowerBook,” it’s likely unique. But if I leave it as the default, it might be “Rosyna’s MacBook Air,” which reveals my name. [[ATUserDefaults sharedInstance] diskUsageInfo]returned a dictionary for each media type (apps, books, music, movies, et cetera). The keys were_PhysicalSize, which gave the size of the resources in bytes, and_Count, which gave the number of assets of a specific media type that were synchronized. While_PhysicalSizeand_Countcould be used individually to help create a globally unique identifier, creating a hash of them together is almost guaranteed to make one that can be used to track users across apps—and maybe across devices if users synced multiple iOS devices to a single PC or Mac.
All of this information was accessible because the preference domain that AirTrafficDevice uses to store data, com.apple.atc, was not protected. At all… For example, to get the list of DSIDs, you could simply call CFPreferencesCopyAppValue(CFSTR("ATDeviceSettingPreExistingStoreAccountIDs"), CFSTR("com.apple.atc")), which returned a data blob. Upon inspecting the data blob, I noticed that it started with “bplist”, indicating a Binary Property List. After further investigation of the plist entries, I discovered it was actually an NSKeyedArchiver instance. Unarchiving this value revealed the three DSIDs I had used with my iPhone. Sigh. It was somewhat moot as I could have just called [[ATDeviceSettings sharedInstance] getPreExistingStoreIdentifiers], which would automatically decode the values from the preference keys.
Apple addressed this in both iOS 18.7 and iOS 26 et fam by locking down the com.apple.atc preferences domain.
I hope you learned something from this post, and depending on the results of the GoFundMe, I’d like to write more posts of this type if enough people want them.