Skip to content

Fix: restore NSPersistentStoreFileProtectionKey and iCloud backup exclusion for health data (CWE-311, CWE-312) - #750

Open
iaohkut-from-NightWolf-Team wants to merge 1 commit into
carekit-apple:mainfrom
iaohkut-from-NightWolf-Team:fix/restore-health-data-file-protection
Open

Fix: restore NSPersistentStoreFileProtectionKey and iCloud backup exclusion for health data (CWE-311, CWE-312)#750
iaohkut-from-NightWolf-Team wants to merge 1 commit into
carekit-apple:mainfrom
iaohkut-from-NightWolf-Team:fix/restore-health-data-file-protection

Conversation

@iaohkut-from-NightWolf-Team

Copy link
Copy Markdown

Security Fix — Missing File Protection and Backup Exclusion (CWE-311, CWE-312)

Summary

Commit 659fbb2 (v3.1.7, 2025-05-13) introduced a regression that removed two security controls protecting the CareKit health data SQLite store. This PR restores both controls.

Issue 1 — Missing NSPersistentStoreFileProtectionKey (CWE-311)

Root cause: NSPersistentStoreFileProtectionKey was removed from NSPersistentStoreDescription in loadStore(into:).

On iOS, CoreData's SQLite files (.sqlite, .sqlite-wal, .sqlite-shm) do not inherit the parent directory's file protection class. Without NSPersistentStoreFileProtectionKey, these files use the iOS default (completeUntilFirstUserAuthentication) instead of the developer-specified .complete class.

Impact: Health data (OCKPatient, OCKTask, OCKOutcome, OCKCarePlan, OCKContact) is accessible using forensic tools when the device is locked — as long as it was unlocked at least once since the last reboot. The intended complete protection requires the device to be actively unlocked.

Vulnerable code (current):

let descriptor = NSPersistentStoreDescription()
descriptor.url = storeURL
descriptor.type = NSSQLiteStoreType
descriptor.shouldAddStoreAsynchronously = false
// NSPersistentStoreFileProtectionKey missing — regression from 659fbb2
container.persistentStoreDescriptions = [descriptor]

Fix (this PR):

descriptor.setOption(storeType.securityClass as NSObject, forKey: NSPersistentStoreFileProtectionKey)

Issue 2 — Incorrect iCloud Backup Exclusion API (CWE-312)

Root cause: The correct URLResourceValues.isExcludedFromBackup = true (set via URL.setResourceValues after loadPersistentStores) was replaced with FileAttributeKey(kCFURLIsExcludedFromBackupKey as String): true in createDirectory attributes.

kCFURLIsExcludedFromBackupKey is a URL resource key (NSURLIsExcludedFromBackupKey), not a POSIX FileAttributeKey. It is silently ignored by FileManager.createDirectory. Additionally, even if the directory exclusion were set correctly, it does not propagate to files CoreData creates inside it.

Impact: SQLite health data files are included in iCloud and iTunes backups. If a user's Apple ID is compromised, an attacker can download the backup and read all health records.

Vulnerable code (current):

let attributes: [FileAttributeKey: Any] = [
    FileAttributeKey(kCFURLIsExcludedFromBackupKey as String): true,  // silently ignored
    FileAttributeKey.protectionKey: protection
]
try fileManager.createDirectory(at: storeDirectory, withIntermediateDirectories: true, attributes: attributes)
// SQLite files created after this have NO backup exclusion set

Fix (this PR): Removes the ineffective FileAttributeKey entry and restores the correct URL.setResourceValues approach called in the loadPersistentStores completion handler — after the store file is created.


Affected Versions

  • 3.1.7 (regression introduced in 659fbb2)
  • 4.0.0
  • 4.1.0

Pre-regression Versions (not affected)

  • ≤ 3.1.6

Note for Apple Product Security

This regression was identified via static analysis and git history comparison. If preferred, security details can also be reported to product-security@apple.com.

References

…for health data store (CWE-311, CWE-312)

Commit 659fbb2 (v3.1.7) removed two security controls from OCKStore's
loadStore function:

1. `NSPersistentStoreFileProtectionKey` was removed from
   NSPersistentStoreDescription. On iOS, CoreData's SQLite files do not
   inherit the parent directory's file protection class — it must be set
   explicitly via this key. Without it, the .sqlite/.sqlite-wal/.sqlite-shm
   files use the default `completeUntilFirstUserAuthentication` instead of
   the intended `complete`, making health data accessible when the device is
   locked (after first unlock since boot).

2. The correct `URLResourceValues.isExcludedFromBackup = true` (set via
   URL.setResourceValues after loadPersistentStores) was replaced with
   `FileAttributeKey(kCFURLIsExcludedFromBackupKey as String)` passed to
   createDirectory. This is the wrong API — kCFURLIsExcludedFromBackupKey
   is a URL resource key and is silently ignored by FileManager. As a
   result, the SQLite health data files are included in iCloud/iTunes
   backups.

This commit restores both controls to their pre-3.1.7 state and removes
the ineffective FileAttributeKey backup exclusion attempt.

Co-Authored-By: iaohkut <thb2601@gmail.com>
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.

2 participants