Skip to content

fix(privacy): correct invalid values in PrivacyInfo.xcprivacy - #446

Open
dishanest wants to merge 1 commit into
segmentio:mainfrom
dishanest:patch-1
Open

fix(privacy): correct invalid values in PrivacyInfo.xcprivacy#446
dishanest wants to merge 1 commit into
segmentio:mainfrom
dishanest:patch-1

Conversation

@dishanest

Copy link
Copy Markdown

Scope note up front: this PR does not touch NSPrivacyTracking or NSPrivacyTrackingDomains. I'm aware of #318, where the tracking-domains array had to be removed because listing api.segment.io caused iOS to block SDK connections for apps without ATT consent. Nothing here can reproduce that: NSPrivacyCollectedDataTypes and NSPrivacyAccessedAPITypes have no runtime enforcement behavior. They only feed the aggregated privacy report Xcode generates for the embedding app.

Why this matters downstream

Xcode unions every embedded framework's manifest into the host app's generated privacy report. Because analytics-swift builds as its own framework and ships this plist, every app embedding the SDK currently gets an "Advertising Data → Developer's Advertising or Marketing" line attributed to Segment — sitting in the same report as this file's own NSPrivacyTracking = false. App developers see a contradiction they did not write and cannot fix without vendoring the SDK.

Four corrections

1. NSPrivacyCollectedDataTypeDeviceID has an empty-string purpose

<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
    <string></string>
</array>

"" is not one of Apple's six purpose constants. The file is valid plist, so plutil -lint passes and nothing errors — it is just semantically meaningless.

The SDK sends device.id (identifierForVendor) with every event — Sources/Segment/Plugins/Context.swift:96:

"id": device.identifierForVendor ?? ""

For an analytics SDK the truthful purpose is NSPrivacyCollectedDataTypePurposeAnalytics.

2. App Name and App Version are not data-type constants

Both entries use free text where an NSPrivacyCollectedDataType* constant belongs. Apple's enumeration has no entry for app name, version, or build, so there is nothing to map these onto.

The SDK does read them (Context.swift:70-77), but they are app metadata rather than one of Apple's enumerated collected data types. Proposing deletion.

3. NSPrivacyCollectedDataTypeAdvertisingData — the core SDK does not collect it

$ grep -rn "ASIdentifierManager\|advertisingIdentifier\|IDFA\|advertisingId" Sources/Segment --include="*.swift"
(no matches)

IDFA collection requires a separate plugin the developer adds explicitly. The core SDK has no path to advertising data, so this declaration is inaccurate for every consumer of the base package.

This is also the entry doing the most downstream damage, since it is what surfaces "Advertising Data" in host apps' privacy reports.

4. 1C8F.1 should be CA92.1

1C8F.1 covers user defaults shared across an App Group. The SDK's suites are not app groups — Sources/Segment/Utilities/Storage/Storage.swift:24 and Sources/Segment/Utilities/Storage/Types/DirectoryStore.swift:54:

UserDefaults(suiteName: "com.segment.storage.\(writeKey)")!

No group. prefix, so this is not an entitled App Group and resolves to app-local storage. The lifecycle plugins additionally use plain UserDefaults.standard (Plugins/Platforms/iOS/iOSLifecycleEvents.swift:35-36, 72-73, and the macOS/watchOS equivalents).

Both are exactly what CA92.1 describes: "read and write information that is only accessible to the app itself."

C56D.1 does not apply either — it requires the SDK to touch user defaults only through a wrapper the app calls, and explicitly forbids using the data for the SDK's own purposes or sending it off-device. The SDK stores its own event queue there.

Deliberately left out

NSPrivacyCollectedDataTypeUserID arguably belongs here, since identify() accepts a userId that is transmitted. I left it out to keep this diff to provable corrections only — happy to add it in this PR or a follow-up if you'd prefer it declared.

Four corrections, none touching NSPrivacyTracking or NSPrivacyTrackingDomains:

- NSPrivacyCollectedDataTypeDeviceID declared an empty-string purpose, which
  is not one of Apple's purpose constants. Set to Analytics, matching the
  identifierForVendor sent with every event (Context.swift:96).
- "App Name" and "App Version" were free text where an
  NSPrivacyCollectedDataType constant belongs. Apple's enumeration has no
  entry for app metadata, so both are removed.
- NSPrivacyCollectedDataTypeAdvertisingData is removed. The core SDK has no
  IDFA references at all; that collection requires a separate plugin the
  developer adds explicitly.
- The UserDefaults reason code 1C8F.1 (App Group storage) becomes CA92.1
  (app-local). The SDK's suites are "com.segment.storage.<writeKey>" with no
  group. prefix (Storage.swift:24, DirectoryStore.swift:54), plus
  UserDefaults.standard in the lifecycle plugins.
@dishanest

Copy link
Copy Markdown
Author

@didiergarcia @wenxi-zeng any chance of a review on this? It's been two weeks.

Still merges clean against main (c9a0d63). Scope is unchanged: four wrong values in PrivacyInfo.xcprivacy, and nothing touching NSPrivacyTracking or NSPrivacyTrackingDomains.

If the advertising-data one is the part that needs a maintainer decision, I can split it out so the other three land on their own. Let me know either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant