swift-security-expert
Use when working with iOS/macOS Keychain Services (SecItem queries, kSecClass, OSStatus errors), biometric authentication (LAContext, Face ID, Touch ID), CryptoKit (AES-GCM, ChaChaPoly, ECDSA, ECDH, HPKE, ML-KEM), Secure Enclave, secure credential storage (OAuth tokens, API keys), certificate pinnin
By ivan-magda · 757 installs
npx skills add ivan-magda/swift-security-skill --skill swift-security-expert
Source repository · Upstream listing
Keychain & Security Expert Skill
Philosophy: Non opinionated, correctness focused. This skill provides facts, verified patterns, and Apple documented best practices — not architecture mandates. It covers iOS 13+ as a minimum deployment target, with modern recommendations targeting iOS 17+ and forward looking guidance through iOS 26 (post quantum). Every code pattern is grounded in Apple documentation, DTS engineer posts (Quinn "The Eskimo!"), WWDC sessions, and OWASP MASTG — never from memory alone.
What this skill is: A reference for reviewing, improving, and implementing keychain operations, biometric authentication, CryptoKit cryptography, credential lifecycle management, certificate trust, and compliance mapping on Apple platforms.
What this skill is not: A networking guide, a server side security reference, or an App Transport Security manual. TLS configuration, server certificate management, and backend auth architecture are out of scope except where they directly touch client side keychain or trust APIs.
Decision Tree
Determine the user's intent, then follow the matching branch. If ambiguous, ask.
Branch 1 — REVIEW (Audit Existing Code)
Goal: Systematically evaluate existing keychain/security code for correctness, security, and compliance.
Procedure:
1. Run the Top Level Review Checklist (below) against the code under review. Score each item ✅ / ❌ / ⚠️ N/A.
2. For each ❌ failure , load the cited reference file and locate the specific anti pattern or correct pattern.
3. Cross check anti patterns — scan code against all 10 entries in common anti patterns.md . Pay special attention to: UserDefaults for secrets ( 1), hardcoded keys ( 2), LAContext.evaluatePolicy() as sole auth gate ( 3), ignored OSStatus ( 4).
4. Check compliance — if the project requires OWASP MASVS or enterprise audit readiness, map findings to compliance owasp mapping.md categories M1, M3, M9, M10.
5. Report format: For each finding, state: what's wrong → which reference file covers it → the ✅ correct pattern → severity (CRITICAL / HIGH / MEDIUM).
Key reference files for review:
Start with: common anti patterns.md (backbone — covers 10 most dangerous patterns)
Then domain specific files based on what the code does
Finish with: compliance owasp mapping.md (if compliance is relevant)
Branch 2 — IMPROVE (Migrate / Modernize)
Goal: Upgrade existing code from insecure storage, deprecated APIs, or legacy patterns to current best practices.
Procedure:
1. Identify the migration type:
Insecure storage → Keychain: Load migration legacy stores.md + credential storage patterns.md
Legacy Security framework → CryptoKit: Load cryptokit symmetric.md or cryptokit public key.md + migration legacy stores.md
RSA → Elliptic Curve: Load cryptokit public key.md (RSA migration section)
GenericPassword → InternetPassword (AutoFill): Load keychain item classes.md (migration section)
LAContext only → Keychain bound biometrics: Load biometric authentication.md
File based keychain → Data protection keychain (macOS): Load keychain fundamentals.md (TN3137 section)
Single app → Shared keychain (extensions): Load keychain sharing.md
Leaf pinning → SPKI/CA pinning: Load certificate trust.md
2. Follow the migration pattern in the relevant reference file. Every migration section includes: pre migration validation, atomic migration step, legacy data secure deletion, post migration verification.
3. Run the domain specific checklist from the reference file after migration completes.
4. Verify no regressions using guidance from testing security code.md .
Branch 3 — IMPLEMENT (Build from Scratch)
Goal: Build new keychain/security functionality correctly from the start.
Procedure:
1. Identify which domain(s) the task touches. Use the Domain Selection Guide below.
2. Load the relevant reference file(s). Follow ✅ code patterns — never deviate from them for the core security logic.
3. Apply Core Guidelines (below) to every implementation.
4. Run the domain specific checklist before considering the implementation complete.
5. Add tests following testing security code.md — protocol based abstraction for unit tests, real keychain for integration tests on device.
Domain Selection Guide:
If the task involves… Load these reference files
Storing/reading a password or token keychain fundamentals.md + credential storage patterns.md
Choosing which kSecClass to use keychain item classes.md
Setting when items are accessible keychain access control.md
Face ID / Touch ID gating biometric authentication.md + keychain access control.md
Hardware backed keys secure enclave.md
Encrypting / hashing data cryptokit symmetric.md
Signing / key exchange / HPKE cryptokit public key.md
OAuth tokens / API keys / logout credential storage patterns.md
Sharing between app and extension keychain sharing.md
TLS pinning / client certificates certificate trust.md
Replacing UserDefaults / plist secrets migration legacy stores.md
Writing tests for security code testing security code.md
Enterprise audit / OWASP compliance compliance owasp mapping.md
Core Guidelines
These seven rules are non negotiable. Every keychain/security implementation must satisfy all of them.
1. Never ignore OSStatus . Every SecItem call returns an OSStatus . Use an exhaustive switch covering at minimum: errSecSuccess , errSecDuplicateItem ( 25299), errSecItemNotFound ( 25300), errSecInteractionNotAllowed ( 25308). Silently discarding the return value is the root cause of most keychain bugs. → keychain fundamentals.md
2. Never use LAContext.evaluatePolicy() as a standalone auth gate. This returns a Bool that is trivially patchable at runtime via Frida. Biometric authentication must be keychain bound: store the secret behind SecAccessControl with .biometryCurrentSet , then let the keychain prompt for Face ID/Touch ID during SecItemCopyMatching . The keychain handles authentication in the Secure Enclave — there is no Bool to patch. → biometric authentication.md
3. Never store secrets in UserDefaults , Info.plist , .xcconfig , or NSCoding archives. These produce plaintext artifacts readable from unencrypted backups. The Keychain is the only Apple sanctioned store for credentials. → credential storage patterns.md , common anti patterns.md
4. Never call SecItem on @MainActor . Every keychain call is an IPC round trip to securityd that blocks the calling thread. Use a dedicated actor (iOS 17+) or serial DispatchQueue (iOS 13–16) for all keychain access. → keychain fundamentals.md
5. Always set kSecAttrAccessible explicitly. The system default ( kSecAttrAccessibleWhenUnlocked ) breaks all background operations and may not match your threat model. Choose the most restrictive class that satisfies your access pattern. For background tasks: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly . For highest sensitivity: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly . → keychain access control.md
6. Always use the add or update pattern. SecItemAdd followed by SecItemUpdate on errSecDuplicateItem . Never delete then add (creates a race window and destroys persistent references). Never call SecItemAdd without handling the duplicate case. → keychain fundamentals.md
7. Always target the data protection keychain on macOS. Set kSecUseDataProtectionKeychain: true for every SecItem call on macOS targets. Without it, queries silently route to the legacy file based keychain which has different behavior, ignores unsupported attributes, and cannot use biometric protection or Secure Enclave keys. Mac Catalyst and iOS on Mac do this automatically. → keychain fundamentals.md
Quick Reference Tables
Accessibility Constants — Selection Guide
Constant When Decryptable Survives Backup Survives Device Migration Background Safe Use When
WhenPasscodeSetThisDeviceOnly Unlocked + passcode set ❌ ❌ ❌ Highest security secrets; removed if passcode removed
WhenUnlockedThisDeviceOnly Unlocked ❌ ❌ ❌ Device bound secrets not needed in background
WhenUnlocked Unlocked ✅ ✅ ❌ Syncable secrets (system default — avoid implicit use)
AfterFirstUnlockThisDeviceOnly After first unlock → restart ❌ ❌ ✅ Background tasks, push handlers, device bound
AfterFirstUnlock After first unlock → restart ✅ ✅ ✅ Background tasks that must survive restore
Deprecated (never use): kSecAttrAccessibleAlways , kSecAttrAccessibleAlwaysThisDeviceOnly — deprecated iOS 12.
Rule of thumb: Need background access (push handlers, background refresh)? Start with AfterFirstUnlockThisDeviceOnly . Foreground only? Start with WhenUnlockedThisDeviceOnly . Tighten to WhenPasscodeSetThisDeviceOnly for high value secrets. Use non ThisDeviceOnly variants only when iCloud sync or backup migration is required.
CryptoKit Algorithm Selection
Need Algorithm Min iOS Notes
Hash data SHA256 / SHA384 / SHA512 13 SHA3 256 / SHA3 512 available iOS 18+
Authenticate data (MAC) HMAC<SHA256 13 Always verify with constant time comparison (built in)
Encrypt data (authenticated) AES.GCM 13 256 bit key, 96 bit nonce, 128 bit tag. Never reuse nonce with same key
Encrypt data (mobile optimized) ChaChaPoly 13 Better on devices without AES NI (older Apple Watch)
Sign data P256.Signing / Curve25519.Signing 13 Use P256 for interop, Curve25519 for performance
Key agreement P256.KeyAgreement / Curve25519.KeyAgreement 13 Always derive symmetric key via HKDF — never use raw shared secret
Hybrid public key encryption HPKE 17 Replaces manual ECDH+HKDF+AES GCM chains
Hardware backed signing SecureEnclave.P256.Signing 13 P256 only; key never leaves hardware
Post quantum key exchange MLKEM768 26 Formal verification (ML KEM FIPS 203)
Post quantum signing M