-
Notifications
You must be signed in to change notification settings - Fork 1
fix: prevent keychain persistence on app uninstall #299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements encryption for keychain data to prevent persistence after app uninstall. Since iOS keeps keychain data by default after uninstall, the solution encrypts all keychain entries with a key stored in the App Group directory (which is deleted on uninstall). The app also detects and wipes orphaned keychain data on fresh installs when the encryption key is missing.
Key Changes:
- Added
KeychainCryptoutility class with AES-GCM encryption/decryption for keychain data - Modified keychain accessibility from
AfterFirstUnlocktoAfterFirstUnlockThisDeviceOnlyto prevent iCloud sync - Implemented orphaned keychain detection and cleanup on app launch
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Bitkit/Utilities/KeychainCrypto.swift | New encryption utility providing AES-GCM encryption/decryption with key management |
| Bitkit/Utilities/Keychain.swift | Integrated encryption/decryption into save/load operations and updated accessibility attribute |
| Bitkit/Utilities/Errors.swift | Added failedToDecrypt error case for decryption failures |
| Bitkit/Utilities/AppReset.swift | Added encryption key deletion and App Group UserDefaults cleanup to wipe operation |
| Bitkit/AppScene.swift | Added orphaned keychain detection and cleanup on app launch |
| BitkitTests/KeychainCryptoTests.swift | Comprehensive test suite for encryption/decryption functionality |
| BitkitTests/KeychainTests.swift | Added encryption integration tests and updated existing tests |
| BitkitTests/KeychainiCloudSyncTests.swift | New test suite verifying keychain items don't sync to iCloud |
| Bitkit.xcodeproj/project.pbxproj | Added KeychainCrypto.swift to project build configuration |
| let thisDeviceOnlyAttributes = [ | ||
| kSecAttrAccessibleWhenUnlocked as String, | ||
| kSecAttrAccessibleAfterFirstUnlock as String, | ||
| kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String, | ||
| kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String, | ||
| ] | ||
|
|
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thisDeviceOnlyAttributes array is declared but never used. Remove this unused variable or use it in the validation logic below.
| let thisDeviceOnlyAttributes = [ | |
| kSecAttrAccessibleWhenUnlocked as String, | |
| kSecAttrAccessibleAfterFirstUnlock as String, | |
| kSecAttrAccessibleWhenUnlockedThisDeviceOnly as String, | |
| kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String, | |
| ] |
| try KeychainCrypto.deleteKey() | ||
| let loadedKey = try KeychainCrypto.getOrCreateKey() |
Copilot
AI
Jan 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test verifies that getOrCreateKey works after deletion but doesn't verify key persistence. The comment on line 56 acknowledges keys differ after deletion. Consider testing actual key persistence by retrieving the key without calling deleteKey() in between, which would verify the load-from-file functionality.
Description
The default Keychain behavior is keep the data after uninstall and there is no flag to change it. This was causing the seed and other sensitive data being persisted and recovered on app re-install.
The solution is encrypt Keychain data with a key that is deleted on app uninstall, making the persisted keychain data useless.
Also, on fresh install, the app checks for orphaned keychain data and wipes it
Manual testing scenarios
Linked Issues/Tasks
Closes #293
Screenshot / Video
Insert relevant screenshot / recording