{"id":"0316da7c-299b-448e-867d-671919cc84fa","shortId":"5nehcF","kind":"skill","title":"swift-security","tagline":"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)","description":"# Keychain & Security Expert Skill\n\n> **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.\n>\n> **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.\n>\n> **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.\n\n---\n\n## Contents\n\n- [Decision Tree](#decision-tree)\n- [Domain Selection Guide](#domain-selection-guide)\n- [Agent Behavioral Rules](#agent-behavioral-rules)\n- [Common Mistakes](#common-mistakes)\n- [Top-Level Review Checklist](#top-level-review-checklist)\n- [Version Reference Table](#version-reference-table)\n- [Self-Review Gate](#self-review-gate)\n\n## Decision Tree\n\nDetermine the user's intent, then follow the matching branch. If ambiguous, ask.\n\n```\n                        ┌─────────────────────┐\n                        │  What is the task?   │\n                        └─────────┬───────────┘\n               ┌──────────────────┼──────────────────┐\n               ▼                  ▼                  ▼\n          ┌─────────┐      ┌───────────┐      ┌────────────┐\n          │ REVIEW  │      │  IMPROVE  │      │ IMPLEMENT  │\n          │         │      │           │      │            │\n          │ Audit   │      │ Migrate / │      │ Build from │\n          │ existing│      │ modernize │      │ scratch    │\n          │ code    │      │ existing  │      │            │\n          └────┬────┘      └─────┬─────┘      └─────┬──────┘\n               │                 │                   │\n               ▼                 ▼                   ▼\n        Run Top-Level      Identify gap         Identify which\n        Review Checklist   (legacy store?        domain(s) apply,\n        (§ below) against  wrong API?            load reference\n        the code.          missing auth?)        file(s), follow\n        Flag each item     Load migration +      ✅ patterns.\n        as ✅ / ❌ /       domain-specific        Implement with\n        ⚠️ N/A.           reference files.       add-or-update,\n        For each ❌,       Follow ✅ patterns,    proper error\n        cite the           verify with domain     handling, and\n        reference file     checklist.             correct access\n        and specific                              control from\n        section.                                  the start.\n```\n\n---\n\n### Branch 1 — REVIEW (Audit Existing Code)\n\n**Goal:** Systematically evaluate existing keychain/security code for correctness, security, and compliance.\n\n**Procedure:**\n\n1. **Run the Top-Level Review Checklist** (below) against the code under review. Score each item ✅ / ❌ / ⚠️ N/A.\n2. **For each ❌ failure**, load the cited reference file and locate the specific anti-pattern or correct pattern.\n3. **Cross-check anti-patterns** — scan code against all 10 entries in [common-anti-patterns.md](references/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).\n4. **Check compliance** — if the project requires OWASP MASVS or enterprise audit readiness, map findings to [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md) categories M1, M3, M9, M10.\n5. **Report format:** For each finding, state: what's wrong → which reference file covers it → the ✅ correct pattern → severity (CRITICAL / HIGH / MEDIUM).\n\n**Key reference files for review:**\n\n- Start with: [common-anti-patterns.md](references/common-anti-patterns.md) (backbone — covers 10 most dangerous patterns)\n- Then domain-specific files based on what the code does\n- Finish with: [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md) (if compliance is relevant)\n\n---\n\n### Branch 2 — IMPROVE (Migrate / Modernize)\n\n**Goal:** Upgrade existing code from insecure storage, deprecated APIs, or legacy patterns to current best practices.\n\n**Procedure:**\n\n1. **Identify the migration type:**\n   - Insecure storage → Keychain: Load [migration-legacy-stores.md](references/migration-legacy-stores.md) + [credential-storage-patterns.md](references/credential-storage-patterns.md)\n   - Legacy Security framework → CryptoKit: Load [cryptokit-symmetric.md](references/cryptokit-symmetric.md) or [cryptokit-public-key.md](references/cryptokit-public-key.md) + [migration-legacy-stores.md](references/migration-legacy-stores.md)\n   - RSA → Elliptic Curve: Load [cryptokit-public-key.md](references/cryptokit-public-key.md) (RSA migration section)\n   - GenericPassword → InternetPassword (AutoFill): Load [keychain-item-classes.md](references/keychain-item-classes.md) (migration section)\n   - LAContext-only → Keychain-bound biometrics: Load [biometric-authentication.md](references/biometric-authentication.md)\n   - File-based keychain → Data protection keychain (macOS): Load [keychain-fundamentals.md](references/keychain-fundamentals.md) (TN3137 section)\n   - Single app → Shared keychain (extensions): Load [keychain-sharing.md](references/keychain-sharing.md)\n   - Leaf pinning → SPKI/CA pinning: Load [certificate-trust.md](references/certificate-trust.md)\n\n2. **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.\n\n3. **Run the domain-specific checklist** from the reference file after migration completes.\n\n4. **Verify no regressions** using guidance from [testing-security-code.md](references/testing-security-code.md).\n\n---\n\n### Branch 3 — IMPLEMENT (Build from Scratch)\n\n**Goal:** Build new keychain/security functionality correctly from the start.\n\n**Procedure:**\n\n1. **Identify which domain(s) the task touches.** Use the Domain Selection Guide below.\n2. **Load the relevant reference file(s).** Follow ✅ code patterns — never deviate from them for the core security logic.\n3. **Apply Core Guidelines** (below) to every implementation.\n4. **Run the domain-specific checklist** before considering the implementation complete.\n5. **Add tests** following [testing-security-code.md](references/testing-security-code.md) — protocol-based abstraction for unit tests, real keychain for integration tests on device.\n\n**Domain Selection Guide:**\n\n| If the task involves…                  | Load these reference files                                    |\n| -------------------------------------- | ------------------------------------------------------------- |\n| Storing/reading a password or token    | [keychain-fundamentals.md](references/keychain-fundamentals.md) + [credential-storage-patterns.md](references/credential-storage-patterns.md) |\n| Choosing which `kSecClass` to use      | [keychain-item-classes.md](references/keychain-item-classes.md)                                    |\n| Setting when items are accessible      | [keychain-access-control.md](references/keychain-access-control.md)                                  |\n| Face ID / Touch ID gating              | [biometric-authentication.md](references/biometric-authentication.md) + [keychain-access-control.md](references/keychain-access-control.md)  |\n| Hardware-backed keys                   | [secure-enclave.md](references/secure-enclave.md)                                           |\n| Encrypting / hashing data              | [cryptokit-symmetric.md](references/cryptokit-symmetric.md)                                      |\n| Signing / key exchange / HPKE          | [cryptokit-public-key.md](references/cryptokit-public-key.md)                                     |\n| OAuth tokens / API keys / logout       | [credential-storage-patterns.md](references/credential-storage-patterns.md)                              |\n| Sharing between app and extension      | [keychain-sharing.md](references/keychain-sharing.md)                                         |\n| TLS pinning / client certificates      | [certificate-trust.md](references/certificate-trust.md)                                        |\n| Replacing UserDefaults / plist secrets | [migration-legacy-stores.md](references/migration-legacy-stores.md)                                  |\n| Writing tests for security code        | [testing-security-code.md](references/testing-security-code.md)                                    |\n| Enterprise audit / OWASP compliance    | [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md)                                 |\n\n---\n\n## Core Guidelines\n\nThese seven rules are non-negotiable. Every keychain/security implementation must satisfy all of them.\n\n**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](references/keychain-fundamentals.md)\n\n**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](references/biometric-authentication.md)\n\n**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](references/credential-storage-patterns.md), [common-anti-patterns.md](references/common-anti-patterns.md)\n\n**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](references/keychain-fundamentals.md)\n\n**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](references/keychain-access-control.md)\n\n**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](references/keychain-fundamentals.md)\n\n**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](references/keychain-fundamentals.md)\n\n---\n\n## Quick Reference Tables\n\n### Accessibility Constants — Selection Guide\n\n| Constant                         | When Decryptable             | Survives Backup | Survives Device Migration | Background Safe | Use When                                               |\n| -------------------------------- | ---------------------------- | --------------- | ------------------------- | --------------- | ------------------------------------------------------ |\n| `WhenPasscodeSetThisDeviceOnly`  | Unlocked + passcode set      | ❌              | ❌                        | ❌              | Highest-security secrets; removed if passcode removed  |\n| `WhenUnlockedThisDeviceOnly`     | Unlocked                     | ❌              | ❌                        | ❌              | Device-bound secrets not needed in background          |\n| `WhenUnlocked`                   | Unlocked                     | ✅              | ✅                        | ❌              | Syncable secrets (system default — avoid implicit use) |\n| `AfterFirstUnlockThisDeviceOnly` | After first unlock → restart | ❌              | ❌                        | ✅              | **Background tasks, push handlers, device-bound**      |\n| `AfterFirstUnlock`               | After first unlock → restart | ✅              | ✅                        | ✅              | Background tasks that must survive restore             |\n\n**Deprecated (never use):** `kSecAttrAccessibleAlways`, `kSecAttrAccessibleAlwaysThisDeviceOnly` — deprecated iOS 12.\n\n**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.\n\n### CryptoKit Algorithm Selection\n\n| Need                            | Algorithm                                       | Min iOS | Notes                                                                       |\n| ------------------------------- | ----------------------------------------------- | ------- | --------------------------------------------------------------------------- |\n| Hash data                       | `SHA256` / `SHA384` / `SHA512`                  | 13      | `SHA3_256`/`SHA3_512` available iOS 26+                                     |\n| Authenticate data (MAC)         | `HMAC<SHA256>`                                  | 13      | Always verify with constant-time comparison (built-in)                      |\n| Encrypt data (authenticated)    | `AES.GCM`                                       | 13      | 256-bit key, 96-bit nonce, 128-bit tag. **Never reuse nonce with same key** |\n| Encrypt data (mobile-optimized) | `ChaChaPoly`                                    | 13      | Better on devices without AES-NI (older Apple Watch)                        |\n| Sign data                       | `P256.Signing` / `Curve25519.Signing`           | 13      | Use P256 for interop, Curve25519 for performance                            |\n| Key agreement                   | `P256.KeyAgreement` / `Curve25519.KeyAgreement` | 13      | Always derive symmetric key via `HKDF` — never use raw shared secret        |\n| Hybrid public-key encryption    | `HPKE`                                          | 17      | Replaces manual ECDH+HKDF+AES-GCM chains                                    |\n| Hardware-backed signing         | `SecureEnclave.P256.Signing`                    | 13      | P256 only; key never leaves hardware                                        |\n| Post-quantum key exchange       | `MLKEM768`                                      | 26      | Formal verification (ML-KEM FIPS 203)                                       |\n| Post-quantum signing            | `MLDSA65`                                       | 26      | Formal verification (ML-DSA FIPS 204)                                       |\n| Password → key derivation       | PBKDF2 (via `CommonCrypto`)                     | 13      | ≥600,000 iterations SHA-256 (OWASP 2024)                                    |\n| Key → key derivation            | `HKDF<SHA256>`                                  | 13      | Extract-then-expand; always use info parameter for domain separation        |\n\n### Anti-Pattern Detection — Quick Scan\n\nWhen reviewing code, search for these patterns. Any match is a finding.\n`❌` = insecure pattern signature to detect in user code. `✅` = apply the corrective pattern in the referenced file.\n\n| Search For                                                              | Anti-Pattern                    | Severity | Reference                    |\n| ----------------------------------------------------------------------- | ------------------------------- | -------- | ---------------------------- |\n| `UserDefaults.standard.set` + token/key/secret/password                 | Plaintext credential storage    | CRITICAL | [common-anti-patterns.md](references/common-anti-patterns.md) #1 |\n| Hardcoded base64/hex strings (≥16 chars) in source                      | Hardcoded cryptographic key     | CRITICAL | [common-anti-patterns.md](references/common-anti-patterns.md) #2 |\n| `evaluatePolicy` without `SecItemCopyMatching` nearby                   | LAContext-only biometric gate   | CRITICAL | [common-anti-patterns.md](references/common-anti-patterns.md) #3 |\n| `SecItemAdd` without checking return / `OSStatus`                       | Ignored error code              | HIGH     | [common-anti-patterns.md](references/common-anti-patterns.md) #4 |\n| No `kSecAttrAccessible` in add dictionary                               | Implicit accessibility class    | HIGH     | [common-anti-patterns.md](references/common-anti-patterns.md) #5 |\n| `AES.GCM.Nonce()` inside a loop with same key                           | Potential nonce reuse           | CRITICAL | [common-anti-patterns.md](references/common-anti-patterns.md) #6 |\n| `sharedSecret.withUnsafeBytes` without HKDF                             | Raw shared secret as key        | HIGH     | [common-anti-patterns.md](references/common-anti-patterns.md) #7 |\n| `kSecAttrAccessibleAlways`                                              | Deprecated accessibility        | HIGH     | [keychain-access-control.md](references/keychain-access-control.md) |\n| `SecureEnclave.isAvailable` without `#if !targetEnvironment(simulator)` | Simulator false-negative trap   | MEDIUM   | [secure-enclave.md](references/secure-enclave.md)          |\n| `kSecAttrSynchronizable: true` + `ThisDeviceOnly`                       | Contradictory constraints       | MEDIUM   | [keychain-item-classes.md](references/keychain-item-classes.md)   |\n| `SecTrustEvaluate` (sync, deprecated)                                   | Legacy trust evaluation         | MEDIUM   | [certificate-trust.md](references/certificate-trust.md)       |\n| `kSecClassGenericPassword` + `kSecAttrServer`                           | Wrong class for web credentials | MEDIUM   | [keychain-item-classes.md](references/keychain-item-classes.md)   |\n\n---\n\n## Top-Level Review Checklist\n\nUse this checklist for a rapid sweep across all 14 domains. Each item maps to one or more reference files for deep-dive investigation. For domain-specific deep checks, use the Summary Checklist at the bottom of each reference file.\n\n- [ ] **1. Secrets are in Keychain, not UserDefaults/plist/source** — No credentials, tokens, or cryptographic keys in `UserDefaults`, `Info.plist`, `.xcconfig`, hardcoded strings, or `NSCoding` archives. OWASP M9 (Insecure Data Storage) directly violated. → [common-anti-patterns.md](references/common-anti-patterns.md) #1–2, [credential-storage-patterns.md](references/credential-storage-patterns.md), [migration-legacy-stores.md](references/migration-legacy-stores.md), [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md)\n\n- [ ] **2. Every `OSStatus` is checked** — All `SecItem*` calls handle return codes with exhaustive `switch` or equivalent. No ignored returns. `errSecInteractionNotAllowed` is handled non-destructively (retry later, never delete). → [keychain-fundamentals.md](references/keychain-fundamentals.md), [common-anti-patterns.md](references/common-anti-patterns.md) #4\n\n- [ ] **3. Biometric auth is keychain-bound** — If biometrics are used, authentication is enforced via `SecAccessControl` + keychain access, not `LAContext.evaluatePolicy()` alone. → [biometric-authentication.md](references/biometric-authentication.md), [common-anti-patterns.md](references/common-anti-patterns.md) #3\n\n- [ ] **4. Accessibility classes are explicit and correct** — Every keychain item has an explicit `kSecAttrAccessible` value matching its access pattern (background vs foreground, device-bound vs syncable). No deprecated `Always` constants. → [keychain-access-control.md](references/keychain-access-control.md)\n\n- [ ] **5. No `SecItem*` calls on `@MainActor`** — All keychain operations run on a dedicated `actor` or background queue. No synchronous keychain access in UI code, `viewDidLoad`, or `application(_:didFinishLaunchingWithOptions:)`. → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n\n- [ ] **6. Correct `kSecClass` for each item type** — Web credentials use `InternetPassword` (not GenericPassword) for AutoFill. Cryptographic keys use `kSecClassKey` with proper `kSecAttrKeyType`. App secrets use `GenericPassword` with `kSecAttrService` + `kSecAttrAccount`. → [keychain-item-classes.md](references/keychain-item-classes.md)\n\n- [ ] **7. CryptoKit used correctly** — Nonces never reused with the same key. ECDH shared secrets always derived through `HKDF` before use as symmetric keys. `SymmetricKey` material stored in Keychain, not in memory or files. Crypto operations covered by protocol-based unit tests. → [cryptokit-symmetric.md](references/cryptokit-symmetric.md), [cryptokit-public-key.md](references/cryptokit-public-key.md), [testing-security-code.md](references/testing-security-code.md)\n\n- [ ] **8. Secure Enclave constraints respected** — SE keys are P256 only (classical), never imported (always generated on-device), device-bound (no backup/sync). Availability checks guard against simulator and keychain-access-groups entitlement issues. → [secure-enclave.md](references/secure-enclave.md)\n\n- [ ] **9. Sharing and access groups configured correctly** — `kSecAttrAccessGroup` uses full `TEAMID.group.identifier` format. Entitlements match between app and extensions. No accidental cross-app data exposure. → [keychain-sharing.md](references/keychain-sharing.md)\n\n- [ ] **10. Certificate trust evaluation is current** — Uses `SecTrustEvaluateAsyncWithError` (not deprecated synchronous `SecTrustEvaluate`). Pinning strategy uses SPKI hash or `NSPinnedDomains` (not leaf certificate pinning which breaks on annual rotation). → [certificate-trust.md](references/certificate-trust.md)\n\n- [ ] **11. macOS targets data protection keychain** — All macOS `SecItem*` calls include `kSecUseDataProtectionKeychain: true` (except Mac Catalyst / iOS-on-Mac where it's automatic). → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n\n---\n\n## References Index\n\n| #   | File                             | One-Line Description                                                                                                  | Risk     |\n| --- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------- |\n| 1   | [keychain-fundamentals.md](references/keychain-fundamentals.md)       | SecItem\\* CRUD, query dictionaries, OSStatus handling, actor-based wrappers, macOS TN3137 routing                     | CRITICAL |\n| 2   | [keychain-item-classes.md](references/keychain-item-classes.md)       | Five kSecClass types, composite primary keys, GenericPassword vs InternetPassword, ApplicationTag vs ApplicationLabel | HIGH     |\n| 3   | [keychain-access-control.md](references/keychain-access-control.md)     | Seven accessibility constants, SecAccessControl flags, data protection tiers, NSFileProtection sidebar                | CRITICAL |\n| 4   | [biometric-authentication.md](references/biometric-authentication.md)    | Keychain-bound biometrics, LAContext bypass vulnerability, enrollment change detection, fallback chains               | CRITICAL |\n| 5   | [secure-enclave.md](references/secure-enclave.md)              | Hardware-backed P256 keys, CryptoKit SecureEnclave module, persistence, simulator traps, iOS 26 post-quantum          | HIGH     |\n| 6   | [cryptokit-symmetric.md](references/cryptokit-symmetric.md)         | SHA-2/3 hashing, HMAC, AES-GCM/ChaChaPoly encryption, SymmetricKey management, nonce handling, HKDF/PBKDF2            | HIGH     |\n| 7   | [cryptokit-public-key.md](references/cryptokit-public-key.md)        | ECDSA signing, ECDH key agreement, HPKE (iOS 17+), ML-KEM/ML-DSA post-quantum (iOS 26+), curve selection              | HIGH     |\n| 8   | [credential-storage-patterns.md](references/credential-storage-patterns.md) | OAuth2/OIDC token lifecycle, API key storage, refresh token rotation, runtime secrets, logout cleanup                 | CRITICAL |\n| 9   | [keychain-sharing.md](references/keychain-sharing.md)            | Access groups, Team ID prefixes, app extensions, Keychain Sharing vs App Groups entitlements, iCloud sync             | MEDIUM   |\n| 10  | [certificate-trust.md](references/certificate-trust.md)           | SecTrust evaluation, SPKI/CA/leaf pinning, NSPinnedDomains, client certificates (mTLS), trust policies                | HIGH     |\n| 11  | [migration-legacy-stores.md](references/migration-legacy-stores.md)     | UserDefaults/plist/NSCoding → Keychain migration, secure deletion, first-launch cleanup, versioned migration          | MEDIUM   |\n| 12  | [common-anti-patterns.md](references/common-anti-patterns.md)        | Top 10 AI-generated security mistakes with ❌/✅ code pairs, detection heuristics, OWASP mapping                      | CRITICAL |\n| 13  | [testing-security-code.md](references/testing-security-code.md)       | Protocol-based mocking, simulator vs device differences, CI/CD keychain, Swift Testing, mutation testing              | MEDIUM   |\n| 14  | [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md)    | OWASP Mobile Top 10 (2024), MASVS v2.1.0, MASTG test IDs, M1/M3/M9/M10 mapping, audit readiness                       | MEDIUM   |\n\n---\n\n## Authoritative Sources\n\nThese are the primary sources underpinning all reference files. When in doubt, defer to these over any secondary source.\n\n- **Apple Keychain Services Documentation** — canonical API reference\n- **Apple Platform Security Guide** (updated annually) — architecture and encryption design\n- **TN3137: \"On Mac Keychain APIs and Implementations\"** — macOS data protection vs file-based keychain\n- **Quinn \"The Eskimo!\" DTS Posts** — \"SecItem: Fundamentals\" and \"SecItem: Pitfalls and Best Practices\" (updated through 2025)\n- **WWDC 2019 Session 709** — \"Cryptography and Your Apps\" (CryptoKit introduction)\n- **WWDC 2025 Session 314** — \"Get ahead with quantum-secure cryptography\" (ML-KEM, ML-DSA)\n- **OWASP Mobile Top 10 (2024)** + **MASVS v2.1.0** + **MASTG v2** — compliance framework\n- **CISA/FBI \"Product Security Bad Practices\" v2.0** (January 2025) — hardcoded credentials classified as national security risk\n\n---\n\n## Agent Behavioral Rules\n\n> The sections below govern how an AI agent should behave when using this skill: what's in scope, what's out, tone calibration, common mistakes to avoid, how to select reference files, and output formatting requirements.\n\n### Scope Boundaries — Inclusions\n\nThis skill is authoritative for **client-side Apple platform security** across iOS, macOS, tvOS, watchOS, and visionOS:\n\n- **Keychain Services** — `SecItemAdd`, `SecItemCopyMatching`, `SecItemUpdate`, `SecItemDelete`, query dictionary construction, `OSStatus` handling, actor/thread isolation, the data protection keychain on macOS (TN3137)\n- **Keychain item classes** — `kSecClassGenericPassword`, `kSecClassInternetPassword`, `kSecClassKey`, `kSecClassCertificate`, `kSecClassIdentity`, composite primary keys, AutoFill integration\n- **Access control** — The seven `kSecAttrAccessible` constants, `SecAccessControlCreateWithFlags`, data protection tiers, `NSFileProtection` correspondence\n- **Biometric authentication** — `LAContext` + keychain binding, the boolean gate vulnerability, enrollment change detection, fallback chains, `evaluatedPolicyDomainState`\n- **Secure Enclave** — CryptoKit `SecureEnclave.P256` module, hardware constraints (P256-only, no import, no export, no symmetric), persistence via keychain, simulator traps, iOS 26 post-quantum (ML-KEM, ML-DSA)\n- **CryptoKit symmetric** — SHA-2/SHA-3 hashing, HMAC, AES-GCM, ChaChaPoly, `SymmetricKey` lifecycle, nonce handling, HKDF, PBKDF2\n- **CryptoKit public-key** — ECDSA signing (P256/Curve25519), ECDH key agreement, HPKE (iOS 17+), ML-KEM/ML-DSA (iOS 26+), curve selection\n- **Credential storage patterns** — OAuth2/OIDC token lifecycle, API key storage, refresh token rotation, runtime secret fetching, logout cleanup\n- **Keychain sharing** — Access groups, Team ID prefixes, `keychain-access-groups` vs `com.apple.security.application-groups` entitlements, extensions, iCloud Keychain sync\n- **Certificate trust** — `SecTrust` evaluation, SPKI/CA/leaf pinning, `NSPinnedDomains`, client certificates (mTLS), trust policies\n- **Migration** — UserDefaults/plist/NSCoding → Keychain migration, secure legacy deletion, first-launch cleanup, versioned migration\n- **Testing** — Protocol-based mocking, simulator vs device differences, CI/CD keychain creation, Swift Testing patterns\n- **Compliance** — OWASP Mobile Top 10 (2024), MASVS v2.1.0, MASTG v2 test IDs, CISA/FBI Bad Practices\n\n**Edge cases that ARE in scope:** Client-side certificate loading for mTLS pinning ([certificate-trust.md](references/certificate-trust.md)). Passkey/AutoFill credential storage in Keychain ([keychain-item-classes.md](references/keychain-item-classes.md), [credential-storage-patterns.md](references/credential-storage-patterns.md)). `@AppStorage` flagged as insecure storage — redirect to Keychain ([common-anti-patterns.md](references/common-anti-patterns.md)).\n\n### Scope Boundaries — Exclusions\n\nDo **not** answer the following topics using this skill. Briefly explain they are out of scope and suggest where to look.\n\n| Topic                                          | Why excluded                                                                         | Redirect to                                                                                                                                       |\n| ---------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **App Transport Security (ATS)**               | Server-side TLS policy, not client keychain                                          | Apple's ATS documentation, `Info.plist` NSAppTransportSecurity reference                                                                          |\n| **CloudKit encryption**                        | Server-managed key hierarchy, not client CryptoKit                                   | CloudKit documentation, `CKRecord.encryptedValues`                                                                                                |\n| **Network security / URLSession TLS config**   | Transport layer, not storage layer                                                   | Apple URL Loading System docs; this skill covers only client certificate loading for mTLS                                                         |\n| **Server-side auth architecture**              | Backend JWT issuance, OAuth provider config                                          | OWASP ASVS (Application Security Verification Standard)                                                                                           |\n| **WebAuthn / passkeys server-side**            | Relying party implementation                                                         | Apple \"Supporting passkeys\" documentation; this skill covers client-side `ASAuthorizationController` only where it stores credentials in Keychain |\n| **Code signing / provisioning profiles**       | Build/distribution, not runtime security                                             | Apple code signing documentation                                                                                                                  |\n| **Jailbreak detection**                        | Runtime integrity, not cryptographic storage                                         | OWASP MASTG MSTG-RESILIENCE category                                                                                                              |\n| **SwiftUI `@AppStorage`**                      | Wrapper over `UserDefaults` — out of scope except to flag it as insecure for secrets | [common-anti-patterns.md](references/common-anti-patterns.md) #1 flags it; no deeper coverage                                                                                         |\n| **Cross-platform crypto (OpenSSL, LibSodium)** | Third-party libraries, not Apple frameworks                                          | Respective library documentation                                                                                                                  |\n\n---\n\n### Tone Rules\n\nThis skill is **non-opinionated and correctness-focused**. Tone calibrates based on severity.\n\n**Default tone — advisory.** Use \"consider,\" \"suggest,\" \"one approach is,\" \"a common pattern is\" for: architecture choices (wrapper class design, actor vs DispatchQueue), algorithm selection when multiple valid options exist (P256 vs Curve25519, AES-GCM vs ChaChaPoly), accessibility class selection when the threat model is unclear, testing strategy, code organization.\n\n**Elevated tone — directive.** Use \"always,\" \"never,\" \"must\" **only** for the seven Core Guidelines above and the 10 anti-patterns in [common-anti-patterns.md](references/common-anti-patterns.md). These are security invariants, not style preferences. The exhaustive list of directives:\n\n1. Never ignore `OSStatus` — always check return codes from `SecItem*` calls. → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n2. Never use `LAContext.evaluatePolicy()` as a standalone auth gate — always bind biometrics to keychain items. → [biometric-authentication.md](references/biometric-authentication.md)\n3. Never store secrets in `UserDefaults`, `Info.plist`, `.xcconfig`, or `NSCoding` archives. → [credential-storage-patterns.md](references/credential-storage-patterns.md), [common-anti-patterns.md](references/common-anti-patterns.md)\n4. Never call `SecItem*` on `@MainActor` — always use a background actor or queue. → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n5. Always set `kSecAttrAccessible` explicitly on every `SecItemAdd`. → [keychain-access-control.md](references/keychain-access-control.md)\n6. Always use the add-or-update pattern (`SecItemAdd` → `SecItemUpdate` on `errSecDuplicateItem`). → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n7. Always set `kSecUseDataProtectionKeychain: true` on macOS targets. → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n8. Never reuse a nonce with the same AES-GCM key. → [cryptokit-symmetric.md](references/cryptokit-symmetric.md), [common-anti-patterns.md](references/common-anti-patterns.md)\n9. Never use a raw ECDH shared secret as a symmetric key — always derive through HKDF. → [cryptokit-public-key.md](references/cryptokit-public-key.md), [common-anti-patterns.md](references/common-anti-patterns.md)\n10. Never use `Insecure.MD5` or `Insecure.SHA1` for security purposes. → [cryptokit-symmetric.md](references/cryptokit-symmetric.md), [common-anti-patterns.md](references/common-anti-patterns.md)\n\nIf a pattern is not on this list, use advisory tone. Do not escalate warnings beyond what the reference files support.\n\n**Tone when declining.** When a query falls outside scope, be direct but not dismissive: \"This skill covers client-side keychain and CryptoKit. For ATS configuration, Apple's NSAppTransportSecurity documentation is the right reference.\" State the boundary, suggest an alternative, move on.\n\n---\n\n## Common Mistakes\n\nBefore finalizing any output, scan for all 10. Each links to the reference file containing the correct pattern.\nEach entry is intentionally paired: `❌` incorrect generated behavior and `✅` corrective pattern to use instead.\n\n**Mistake #1 — Generating `LAContext.evaluatePolicy()` as the sole biometric gate.** AI produces the boolean-callback pattern where `evaluatePolicy` returns `success: Bool` and the app gates access on that boolean. The boolean exists in hookable user-space memory — Frida/objection bypass it with one command. **✅ Correct pattern:** Store a secret behind `SecAccessControl` with `.biometryCurrentSet`, retrieve via `SecItemCopyMatching`. → [biometric-authentication.md](references/biometric-authentication.md)\n\n**Mistake #2 — Suggesting `SecureEnclave.isAvailable` without simulator guard.** AI generates `if SecureEnclave.isAvailable { ... }` without `#if !targetEnvironment(simulator)`. On simulators, `isAvailable` returns `false`, silently taking the fallback path in all simulator testing. **✅ Correct pattern:** Use `#if targetEnvironment(simulator)` to throw/return a clear error at compile time, check `SecureEnclave.isAvailable` only in device builds. → [secure-enclave.md](references/secure-enclave.md)\n\n**Mistake #3 — Importing external keys into the Secure Enclave.** AI generates `SecureEnclave.P256.Signing.PrivateKey(rawRepresentation: someData)`. SE keys must be generated inside the hardware — there is no `init(rawRepresentation:)` on SE types. `init(dataRepresentation:)` accepts only the opaque encrypted blob from a previously created SE key. **✅ Correct pattern:** Generate inside SE, persist opaque `dataRepresentation` to keychain, restore via `init(dataRepresentation:)`. → [secure-enclave.md](references/secure-enclave.md)\n\n**Mistake #4 — Using `SecureEnclave.AES` or SE for symmetric encryption.** AI generates references to non-existent SE symmetric APIs. The SE's internal AES engine is not exposed as a developer API. Pre-iOS 26, the SE supports only P256 signing and key agreement. iOS 26 adds ML-KEM and ML-DSA, not symmetric primitives. **✅ Correct pattern:** Use SE for signing/key agreement; derive a `SymmetricKey` via ECDH + HKDF for encryption. → [secure-enclave.md](references/secure-enclave.md), [cryptokit-symmetric.md](references/cryptokit-symmetric.md)\n\n**Mistake #5 — Omitting `kSecAttrAccessible` in `SecItemAdd`.** AI builds add dictionaries without an accessibility attribute. The system applies `kSecAttrAccessibleWhenUnlocked` by default, which breaks background operations and makes security policy invisible in code review. **✅ Correct pattern:** Always set `kSecAttrAccessible` explicitly. → [keychain-access-control.md](references/keychain-access-control.md)\n\n**Mistake #6 — Using `SecItemAdd` without handling `errSecDuplicateItem`.** AI checks only for `errSecSuccess`, or uses delete-then-add. Without duplicate handling, the second save silently fails. Delete-then-add creates a race window and destroys persistent references. **✅ Correct pattern:** Add-or-update pattern. → [keychain-fundamentals.md](references/keychain-fundamentals.md)\n\n**Mistake #7 — Specifying explicit nonces for AES-GCM encryption.** AI creates a nonce manually and passes it to `AES.GCM.seal`. Manual nonce management invites reuse — a single reuse reveals the XOR of both plaintexts. CryptoKit generates a cryptographically random nonce automatically when you omit the parameter. **✅ Correct pattern:** Call `AES.GCM.seal(plaintext, using: key)` without a `nonce:` parameter. → [cryptokit-symmetric.md](references/cryptokit-symmetric.md), [common-anti-patterns.md](references/common-anti-patterns.md) #6\n\n**Mistake #8 — Using raw ECDH shared secret as a symmetric key.** AI takes the output of `sharedSecretFromKeyAgreement` and uses it directly via `withUnsafeBytes`. Raw shared secrets have non-uniform distribution. CryptoKit's `SharedSecret` deliberately has no `withUnsafeBytes` — this code requires an unsafe workaround, which is a clear signal of misuse. **✅ Correct pattern:** Always derive via `sharedSecret.hkdfDerivedSymmetricKey(...)`. → [cryptokit-public-key.md](references/cryptokit-public-key.md), [common-anti-patterns.md](references/common-anti-patterns.md) #7\n\n**Mistake #9 — Claiming SHA-3 was added in iOS 18.** AI confuses the swift-crypto open-source package (which backports SHA-3 to iOS 13+ via its own XKCP implementation) with the CryptoKit framework. SHA-3 family types (`SHA3_256`, `SHA3_384`, `SHA3_512`) were added to CryptoKit in **iOS 26 / macOS 26** (apple/swift-crypto PR #397, tagged [WWDC25]). The swift-crypto package provides SHA-3 at iOS 13+ using its own implementation, but `import CryptoKit` requires iOS 26. **✅ Correct version tags:** SHA-3 in CryptoKit → iOS 26+. SHA-3 in swift-crypto package (`import Crypto`) → iOS 13+. ML-KEM/ML-DSA → iOS 26+. → [cryptokit-symmetric.md](references/cryptokit-symmetric.md)\n\n**Mistake #10 — Missing first-launch keychain cleanup.** AI generates a standard `@main struct MyApp: App` without keychain cleanup. Keychain items survive app uninstallation. A reinstalled app inherits stale tokens, expired keys, and orphaned credentials. **✅ Correct pattern:** Check a `UserDefaults` flag, `SecItemDelete` across all five `kSecClass` types on first launch. → [common-anti-patterns.md](references/common-anti-patterns.md) #9, [migration-legacy-stores.md](references/migration-legacy-stores.md)\n\n---\n\n### Reference File Loading Rules\n\nLoad the **minimum set** of files needed to answer the query. Do not load all 14 — they total ~7,000+ lines and will dilute focus.\n\n| Query type                       | Load these files                                                                   | Reason                                    |\n| -------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------- |\n| \"Review my keychain code\"        | [common-anti-patterns.md](references/common-anti-patterns.md) → then domain-specific files based on what the code does | Anti-patterns file is the review backbone |\n| \"Is this biometric auth secure?\" | [biometric-authentication.md](references/biometric-authentication.md) + [common-anti-patterns.md](references/common-anti-patterns.md) (#3)                     | Boolean gate is the #1 biometric risk     |\n| \"Store a token / password\"       | [keychain-fundamentals.md](references/keychain-fundamentals.md) + [credential-storage-patterns.md](references/credential-storage-patterns.md)                      | CRUD + lifecycle                          |\n| \"Encrypt / hash data\"            | [cryptokit-symmetric.md](references/cryptokit-symmetric.md)                                                           | Symmetric operations                      |\n| \"Sign data / key exchange\"       | [cryptokit-public-key.md](references/cryptokit-public-key.md)                                                          | Asymmetric operations                     |\n| \"Use Secure Enclave\"             | [secure-enclave.md](references/secure-enclave.md) + [keychain-fundamentals.md](references/keychain-fundamentals.md)                                   | SE keys need keychain persistence         |\n| \"Share keychain with extension\"  | [keychain-sharing.md](references/keychain-sharing.md) + [keychain-fundamentals.md](references/keychain-fundamentals.md)                                 | Access groups + CRUD                      |\n| \"Migrate from UserDefaults\"      | [migration-legacy-stores.md](references/migration-legacy-stores.md) + [credential-storage-patterns.md](references/credential-storage-patterns.md)                    | Migration + target patterns               |\n| \"TLS pinning / mTLS\"             | [certificate-trust.md](references/certificate-trust.md)                                                             | Trust evaluation                          |\n| \"Which kSecClass?\"               | [keychain-item-classes.md](references/keychain-item-classes.md)                                                         | Class selection + primary keys            |\n| \"Set up data protection\"         | [keychain-access-control.md](references/keychain-access-control.md)                                                       | Accessibility constants                   |\n| \"Write tests for keychain code\"  | [testing-security-code.md](references/testing-security-code.md)                                                         | Protocol mocks + CI/CD                    |\n| \"OWASP compliance audit\"         | [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md) + [common-anti-patterns.md](references/common-anti-patterns.md)                          | Mapping + detection                       |\n| \"Full security review\"           | [common-anti-patterns.md](references/common-anti-patterns.md) + all files touched by the code                          | Start with anti-patterns, expand          |\n\n**Loading order:** (1) Most specific file for the query. (2) Add [common-anti-patterns.md](references/common-anti-patterns.md) for any review/audit. (3) Add [keychain-fundamentals.md](references/keychain-fundamentals.md) for any `SecItem*` task. (4) Add [compliance-owasp-mapping.md](references/compliance-owasp-mapping.md) only if OWASP/audit is mentioned. (5) Never load files speculatively.\n\n---\n\n### Output Format Rules\n\n**1. Always include ✅/❌ code examples.** Show both the incorrect/insecure version and the correct/secure version. Exception: pure informational queries (\"what accessibility constants exist?\") do not need ❌ examples.\n\n**2. Always cite iOS version requirements.** Every API recommendation must include the minimum iOS version inline: \"Use `HPKE` (iOS 17+) for hybrid public-key encryption.\"\n\n**3. Always cite the reference file.** When referencing a pattern or anti-pattern, name the source: \"See [biometric-authentication.md](references/biometric-authentication.md) for the full keychain-bound pattern.\"\n\n**4. Always include `OSStatus` handling in keychain code.** Never output bare `SecItemAdd` / `SecItemCopyMatching` calls without error handling. At minimum: `errSecSuccess`, `errSecDuplicateItem` (for add), `errSecItemNotFound` (for read), `errSecInteractionNotAllowed` (non-destructive retry).\n\n**5. Always specify `kSecAttrAccessible` in add examples.** Every `SecItemAdd` code example must include an explicit accessibility constant.\n\n**6. State severity for findings.** CRITICAL = exploitable vulnerability. HIGH = silent data loss or wrong security boundary. MEDIUM = suboptimal but not immediately exploitable.\n\n**7. Prefer modern APIs with fallback notes.** Default to iOS 17+ (actor-based). Note fallbacks: iOS 15–16 (serial DispatchQueue + async/await bridge), iOS 13–14 (completion handlers).\n\n**8. Never fabricate citations or WWDC session numbers.** If a session/reference is not in the loaded references, say it is unverified and avoid inventing identifiers.\n\n**9. Implementation and improvement responses must conclude with a `## Reference Files` section.** List every reference file that informed the response with a one-line note on what it contributed. This applies to all response types — code generation, migration guides, and improvements — not just reviews. Example: `- \\`keychain-fundamentals.md\\` — SecItem CRUD and error handling`.\n\n**10. Cite SKILL.md structural sections when they govern the response.** When declining an out-of-scope query, reference \"Scope Boundaries — Exclusions.\" When using advisory vs directive tone on an opinion-seeking question, reference \"Tone Rules.\" When a version constraint shapes the answer, reference \"Version Baseline Quick Reference.\" A brief parenthetical is sufficient — e.g., \"(per Scope Boundaries — Exclusions).\"\n\n---\n\n### Behavioral Boundaries\n\n**Things the agent must do:**\n\n- Ground every code pattern in the reference files. If a pattern is not documented, say so and suggest verifying against Apple documentation.\n- Flag when code is simulator-only tested. Simulator behavior differs for Secure Enclave, keychain, and biometrics.\n- Distinguish compile-time vs runtime errors. SE key import = compile-time. Missing accessibility class = runtime (silent wrong default). Missing OSStatus check = runtime (lost error).\n\n**Things the agent must not do:**\n\n- Do not invent WWDC session numbers. Only cite sessions documented in the reference files.\n- ✅ examples must always use native APIs — never third-party library code (KeychainAccess, SAMKeychain, Valet). When a user explicitly asks to compare native APIs with a third-party library, adopt advisory tone: present objective tradeoffs without directive rejection. Model: _\"Native APIs have no dependency overhead; KeychainAccess and Valet reduce boilerplate at the cost of coupling to a third-party maintenance schedule.\"_ Do not say \"This skill does not recommend...\" — that is directive output outside the Core Guidelines.\n- Do not claim Apple APIs are buggy without evidence. Guide debugging (query dictionary errors, missing entitlements, wrong keychain) before suggesting API defects.\n- Do not generate Security framework code when CryptoKit covers the use case (iOS 13+).\n- Do not output partial keychain operations. Never show `SecItemAdd` without `errSecDuplicateItem` fallback. Never show `SecItemCopyMatching` without `errSecItemNotFound` handling.\n- Do not escalate tone beyond what the reference files support.\n\n---\n\n### Cross-Reference Protocol\n\n- **Canonical source:** Each pattern has one primary reference file (per the References Index above).\n- **Brief mention + redirect elsewhere:** Other files get a one-sentence summary, not the full code example.\n- **Agent behavior:** Cite the canonical file. Load it for detail. Do not reconstruct patterns from secondary mentions.\n\n---\n\n### Version Baseline Quick Reference\n\n| API / Feature                                 | Minimum iOS                     | Common AI mistake           |\n| --------------------------------------------- | ------------------------------- | --------------------------- |\n| CryptoKit (SHA-2, AES-GCM, P256, ECDH)        | 13                              | Claiming iOS 15+            |\n| `SecureEnclave.P256` (CryptoKit)              | 13                              | Claiming iOS 15+            |\n| SHA-3 (`SHA3_256`, `SHA3_384`, `SHA3_512`)    | **26**                          | Claiming iOS 18+ (swift-crypto package confusion) |\n| HPKE (`HPKE.Sender`, `HPKE.Recipient`)        | **17**                          | Claiming iOS 15+ or iOS 18+ |\n| ML-KEM / ML-DSA (post-quantum)                | **26**                          | Conflating with SHA-3       |\n| `SecAccessControl` with `.biometryCurrentSet` | 11.3                            | Claiming iOS 13+            |\n| `kSecUseDataProtectionKeychain` (macOS)       | macOS 10.15                     | Omitting entirely on macOS  |\n| Swift concurrency `actor`                     | 13 (runtime), 17+ (recommended) | Claiming iOS 15 minimum     |\n| `LAContext.evaluatedPolicyDomainState`        | 9                               | Not knowing it exists       |\n| `NSPinnedDomains` (declarative pinning)       | 14                              | Claiming iOS 16+            |\n\n---\n\n### Agent Self-Review Checklist\n\nRun before finalizing any response that includes security code:\n\n- [ ] Every `SecItemAdd` has an explicit `kSecAttrAccessible` value\n- [ ] Every `SecItemAdd` handles `errSecDuplicateItem` with `SecItemUpdate` fallback\n- [ ] Every `SecItemCopyMatching` handles `errSecItemNotFound`\n- [ ] No `LAContext.evaluatePolicy()` used as standalone auth gate\n- [ ] No `SecItem*` calls on `@MainActor` or main thread\n- [ ] macOS code includes `kSecUseDataProtectionKeychain: true`\n- [ ] Secure Enclave code has `#if targetEnvironment(simulator)` guard\n- [ ] No raw ECDH shared secret used as symmetric key\n- [ ] No explicit nonce in `AES.GCM.seal` unless the user has a documented reason\n- [ ] iOS version tags are present for every API recommendation\n- [ ] Reference file is cited for every pattern shown\n- [ ] Severity is stated for every finding (review/audit tasks)\n- [ ] No fabricated WWDC session numbers","tags":["swift","security","ios","skills","dpearson2699","accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills"],"capabilities":["skill","source-dpearson2699","skill-swift-security","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swift-security","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 599 github stars · SKILL.md body (52,934 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:53:45.167Z","embedding":null,"createdAt":"2026-04-22T12:53:47.938Z","updatedAt":"2026-05-18T18:53:45.167Z","lastSeenAt":"2026-05-18T18:53:45.167Z","tsv":"'-2':2167,2601,4767 '-25299':892 '-25300':894 '-25308':896 '-256':1472 '-3':3759,3778,3792,3822,3840,3846,4784,4823 '/3':2168 '/chachapoly':2174 '/ml-dsa':2196,2631,3859 '/sha-3':2602 '000':1469,3942 '1':345,362,422,536,684,873,1540,1711,1742,2080,2933,3057,3299,3993,4115,4154 '10':410,491,2016,2241,2274,2312,2423,2716,3038,3188,3273,3865,4408 '10.15':4834 '11':2046,2255 '11.3':4827 '12':1265,2270 '128':1353 '13':72,1040,1319,1331,1346,1368,1383,1395,1427,1467,1479,2288,3781,3825,3855,4327,4673,4773,4779,4830,4842 '14':1678,2306,3938,4328,4859 '15':4320,4776,4782,4806,4848 '16':1041,1544,4321,4862 '17':83,1035,1413,2192,2627,4199,4313,4803,4844 '18':3764,4794,4809 '2':380,425,515,616,698,912,1554,1743,1750,2097,3070,3357,4122,4180 '2019':2394 '2024':1474,2313,2424,2717 '2025':2392,2404,2438 '203':1447 '204':1460 '256':1321,1347,3796,4786 '26':91,1326,1440,1453,2158,2201,2588,2633,3502,3513,3807,3809,3835,3844,3861,4791,4819 '3':399,431,645,669,717,974,1567,1784,1809,2113,3087,3408,3988,4129,4206 '314':2406 '384':3798,4788 '397':3812 '4':434,435,659,725,1008,1579,1783,1810,2127,3102,3468,4137,4233 '5':458,737,1048,1591,1843,2143,3117,3545,4146,4264 '512':1323,3800,4790 '6':1088,1605,1873,2163,3127,3585,3692,4281 '600':1468 '7':1126,1617,1904,2182,3142,3632,3754,3941,4303 '709':2396 '8':1952,2205,3152,3694,4331 '9':1989,2222,3168,3756,3916,4356,4851 '96':1350 'abstract':746 'accept':3439 'access':336,788,1045,1076,1188,1271,1586,1620,1801,1811,1827,1863,1983,1992,2117,2225,2539,2655,2662,3009,3323,3556,4041,4075,4173,4279,4527 'accident':2008 'across':1676,2499,3906 'actor':1033,1856,2090,2991,3112,4315,4841 'actor-bas':2089,4314 'actor/thread':2517 'ad':3761,3802 'add':316,738,1093,1107,1583,3132,3514,3552,3601,3613,3625,4123,4130,4138,4255,4269 'add-or-upd':315,1092,3131,3624 'adopt':4589 'advisori':2974,3210,4432,4590 'ae':25,1374,1419,2172,2606,3005,3161,3490,3638,4769 'aes-gcm':24,1418,2171,2605,3004,3160,3637,4768 'aes-ni':1373 'aes.gcm':1345 'aes.gcm.nonce':1592 'aes.gcm.seal':3650,3680,4936 'afterfirstunlock':1247 'afterfirstunlockthisdeviceon':1235,1278 'agent':204,208,2446,2456,4471,4541,4737,4863 'agent-behavioral-rul':207 'agreement':1392,2189,2624,3511,3531 'ahead':2408 'ai':2276,2455,3307,3363,3416,3476,3550,3591,3641,3704,3765,3872,4763 'ai-gener':2275 'algorithm':1307,1310,2994 'alon':117,1804 'altern':3261 'alway':1049,1089,1127,1332,1396,1484,1839,1918,1965,3026,3061,3079,3108,3118,3128,3143,3180,3578,3746,4155,4181,4207,4234,4265,4561 'ambigu':254 'annual':2042,2357 'answer':2767,3931,4451 'anti':394,404,1492,1528,3040,3972,4110,4218 'anti-pattern':393,403,1491,1527,3039,3971,4109,4217 'api':41,190,290,527,819,2211,2350,2366,2642,3485,3498,4187,4306,4564,4582,4600,4642,4658,4758,4951 'app':162,602,826,1895,2004,2011,2230,2235,2400,2791,3321,3879,3886,3890 'appl':62,101,144,999,1377,2345,2352,2496,2803,2833,2872,2898,2950,3248,4494,4641 'apple-docu':61 'apple-sanct':998 'apple/swift-crypto':3810 'appli':286,718,1517,3560,4387 'applic':1869,2860 'applicationlabel':2111 'applicationtag':2109 'approach':2979 'appstorag':2752,2916 'architectur':67,174,2358,2851,2986 'archiv':984,1732,3097 'artifact':988 'asauthorizationcontrol':2882 'ask':255,4578 'asv':2859 'asymmetr':4019 'async/await':4324 'at':2794,2805,3246 'atom':634 'attent':417 'attribut':1163,3557 'audit':263,347,446,851,2321,4089 'auth':173,296,429,919,1786,2850,3077,3982,4900 'authent':17,132,934,961,1327,1344,1795,2552 'authorit':2324,2491 'autofil':572,1887,2537 'automat':1182,2069,3671 'avail':1324,1975 'avoid':1232,2475,4353 'back':802,1424,2148 'backbon':489,3978 'backend':172,2852 'background':1059,1079,1200,1225,1240,1252,1270,1274,1829,1858,3111,3566 'backport':3776 'backup':992,1196,1302 'backup/sync':1974 'bad':2434,2725 'bare':4243 'base':500,590,745,1155,1943,2091,2293,2375,2700,2969,3965,4316 'base64/hex':1542 'baselin':4454,4755 'behav':2458 'behavior':205,209,1160,2447,3291,4467,4505,4738 'behind':943,3347 'best':64,533,2388 'better':1369 'beyond':3216,4696 'bind':2555,3080 'biometr':16,131,584,933,1167,1562,1785,1792,2133,2551,3081,3305,3981,3994,4512 'biometric-authentication.md':586,796,972,1805,2128,3085,3354,3984,4224 'biometrycurrentset':946,3350,4826 'bit':1348,1351,1354 'blob':3444 'block':1026 'boilerpl':4609 'bool':924,969,3318 'boolean':2557,3311,3326,3328,3989 'boolean-callback':3310 'bottom':1706 'bound':583,939,1220,1246,1790,1834,1972,2132,4231 'boundari':2486,2763,3258,4296,4428,4465,4468 'branch':252,344,514,668 'break':1057,2040,3565 'bridg':4325 'brief':4458,4720 'briefli':2774 'bug':909 'buggi':4644 'build':265,671,675,3404,3551 'build/distribution':2894 'built':1340 'built-in':1339 'bypass':2135,3337 'calibr':2471,2968 'call':879,1010,1016,1028,1117,1141,1757,1846,2055,3067,3104,3679,4246,4904 'callback':3312 'cannot':1165 'canon':2349,4706,4741 'case':1123,2728,4671 'catalyst':1174,2061 'categori':453,2914 'caus':905 'certif':138,169,834,2017,2037,2250,2672,2680,2736,2843 'certificate-trust.md':614,835,1652,2044,2242,2741,4057 'chachapoli':27,1367,2608,3008 'chain':1421,2141,2564 'chang':2138,2561 'char':1545 'check':402,436,1570,1699,1754,1976,3062,3399,3592,3901,4535 'checklist':220,225,281,334,369,651,731,1668,1671,1703,4867 'choic':2987 'choos':777,1068 'ci/cd':2299,2706,4086 'cisa/fbi':2431,2724 'citat':4334 'cite':325,386,4182,4208,4409,4552,4739,4956 'ckrecord.encryptedvalues':2822 'claim':3757,4640,4774,4780,4792,4804,4828,4846,4860 'class':1072,1587,1657,1812,2528,2989,3010,4065,4528 'classic':1962 'classifi':2441 'cleanup':2220,2266,2652,2694,3871,3882 'clear':3394,3740 'client':185,833,2249,2494,2679,2734,2801,2818,2842,2880,3240 'client-sid':184,2493,2733,2879,3239 'cloudkit':2810,2820 'code':96,270,294,349,355,373,407,504,522,706,847,1499,1516,1575,1760,1866,2281,2890,2899,3020,3064,3574,3732,3957,3969,4081,4106,4157,4240,4273,4392,4476,4498,4570,4665,4735,4876,4911,4917 'com.apple.security.application':2665 'command':3341 'common':211,214,2472,2982,3264,4762 'common-anti-patterns.md':413,487,1006,1538,1552,1565,1577,1589,1603,1615,1740,1781,1807,2271,2760,2931,3043,3100,3166,3186,3199,3690,3752,3914,3958,3986,4092,4099,4124 'common-mistak':213 'commoncrypto':1466 'compar':4580 'comparison':1338 'compil':3397,4515,4524 'compile-tim':4514,4523 'complet':658,736,4329 'complianc':141,360,437,511,853,2429,2712,4088 'compliance-owasp-mapping.md':451,508,854,1748,2307,4090,4139 'composit':2103,2534 'conclud':4362 'concurr':4840 'config':2827,2857 'configur':167,1994,3247 'conflat':4820 'confus':3766,4799 'consid':733,2976 'constant':1189,1192,1336,1840,2118,2544,4076,4174,4280 'constant-tim':1335 'constraint':1641,1955,2572,4448 'construct':2514 'contain':3280 'content':191 'contradictori':1640 'contribut':4385 'control':339,2540 'core':714,719,856,3033,4636 'correct':52,335,357,397,474,679,1519,1816,1874,1907,1995,2965,3282,3293,3342,3385,3451,3525,3576,3622,3677,3744,3836,3899 'correct/secure':4166 'correctness-focus':51,2964 'correspond':2550 'cost':4612 'coupl':4614 'cover':70,471,490,887,1939,2840,2878,3238,4668 'coverag':2938 'creat':1108,3448,3614,3642 'creation':2708 'credenti':37,135,1003,1535,1660,1719,1881,2440,2636,2744,2887,3898 'credential-storage-patterns.md':547,775,822,1004,1744,2206,2750,3098,4002,4049 'critic':477,1537,1551,1564,1602,2096,2126,2142,2221,2287,4286 'cross':401,2010,2940,4703 'cross-app':2009 'cross-check':400 'cross-platform':2939 'cross-refer':4702 'crud':2084,4004,4043,4404 'crypto':1937,2942,3770,3818,3850,3853,4797 'cryptograph':1549,1722,1888,2907,3668 'cryptographi':134,2397,2413 'cryptokit':23,133,552,1306,1905,2151,2401,2568,2598,2615,2819,3244,3665,3724,3789,3804,3832,3842,4667,4765,4778 'cryptokit-public-key.md':557,565,815,1948,2183,3184,3750,4017 'cryptokit-symmetric.md':554,809,1946,2164,3164,3197,3542,3688,3862,4009 'current':532,2021 'curv':563,2202,2634 'curve25519':1388,3003 'curve25519.keyagreement':1394 'curve25519.signing':1382 'danger':493 'data':592,638,808,1130,1315,1328,1343,1363,1380,1736,2012,2049,2121,2370,2520,2546,4008,4014,4071,4291 'datarepresent':3438,3458,3464 'debug':4648 'decis':192,195,241 'decision-tre':194 'declar':4857 'declin':3224,4419 'decrypt':1194 'dedic':1032,1855 'deep':1691,1698 'deep-div':1690 'deeper':2937 'default':1055,1231,2972,3563,4310,4532 'defect':4659 'defer':2338 'delet':640,1105,1778,2262,2690,3599,3611 'delete-then-add':1104,3598,3610 'deliber':3727 'depend':4603 'deploy':76 'deprec':526,1258,1263,1619,1647,1838,2025 'deriv':1397,1463,1477,1919,3181,3532,3747 'descript':2078 'design':2361,2990 'destroy':1113,3619 'destruct':1774,4262 'detail':4746 'detect':1494,1513,2139,2283,2562,2903,4095 'determin':243 'develop':3497 'deviat':709 'devic':756,1198,1219,1245,1371,1833,1969,1971,2297,2704,3403 'device-bound':1218,1244,1832,1970 'dictionari':1584,2086,2513,3553,4650 'didfinishlaunchingwithopt':1870 'differ':1159,2298,2705,4506 'dilut':3946 'direct':182,1738,3024,3056,3232,3713,4434,4596,4632 'discard':898 'dismiss':3235 'dispatchqueu':1038,2993,4323 'distinguish':4513 'distribut':3723 'dive':1692 'doc':2837 'document':63,102,2348,2806,2821,2875,2901,2954,3251,4487,4495,4554,4942 'domain':197,201,284,308,329,497,649,687,694,729,757,1489,1679,1696,3962 'domain-selection-guid':200 'domain-specif':307,496,648,728,1695,3961 'doubt':2337 'dsa':1458,2419,2597,3521,4815 'dts':103,2380 'duplic':1122,3603 'e.g':4462 'ecdh':29,1416,1915,2187,2622,3173,3536,3697,4772,4925 'ecdsa':28,2185,2619 'edg':2727 'elev':3022 'ellipt':562 'elsewher':4723 'enclav':35,965,1171,1954,2567,3415,4023,4509,4916 'encrypt':806,1342,1362,1411,2175,2360,2811,3443,3475,3539,3640,4006,4205 'enforc':1797 'engin':104,3491 'enrol':2137,2560 'enterpris':445,850 'entir':4836 'entitl':1985,2001,2237,2667,4653 'entri':411,3285 'equival':1765 'error':15,324,1574,3395,4248,4406,4519,4538,4651 'errsecduplicateitem':891,1102,3139,3590,4253,4684,4887 'errsecinteractionnotallow':895,1769,4259 'errsecitemnotfound':893,4256,4690,4894 'errsecsuccess':890,3595,4252 'escal':3214,4694 'eskimo':108,2379 'evalu':352,1650,2019,2245,2675,4060 'evaluatedpolicydomainst':2565 'evaluatepolici':1555,3315 'everi':95,626,723,865,877,1014,1139,1751,1817,3123,4186,4271,4369,4475,4877,4884,4891,4950,4958,4965 'evid':4646 'exampl':4158,4179,4270,4274,4401,4559,4736 'except':179,2059,2923,4168 'exchang':813,1438,4016 'exclud':2788 'exclus':2764,4429,4466 'exhaust':885,1762,3053 'exist':267,271,348,353,521,3000,3329,3482,4175,4855 'expand':1483,4112 'expert':45 'expir':3894 'explain':2775 'explicit':1052,1814,1822,3121,3581,3634,4278,4577,4881,4933 'exploit':4287,4302 'export':2579 'expos':3494 'exposur':2013 'extens':605,828,2006,2231,2668,4036 'extern':3410 'extract':1481 'extract-then-expand':1480 'fabric':4333,4970 'face':19,791,953 'fact':57 'fail':3609 'failur':383 'fall':3228 'fallback':2140,2563,3379,4308,4318,4685,4890 'fals':1631,3375 'false-neg':1630 'famili':3793 'featur':4759 'fetch':2650 'file':297,314,333,388,470,482,499,589,625,655,703,767,1154,1524,1688,1710,1936,2074,2334,2374,2480,3220,3279,3920,3928,3952,3964,3974,4102,4118,4149,4211,4366,4371,4481,4558,4700,4714,4725,4742,4954 'file-bas':588,1153,2373 'final':3267,4870 'find':449,463,1508,4285,4966 'finish':506 'fip':1446,1459 'first':1237,1249,2264,2692,3868,3912 'first-launch':2263,2691,3867 'five':2100,3908 'flag':300,2120,2753,2925,2934,3904,4496 'focus':53,2966,3947 'follow':249,299,321,617,705,740,1098,2769 'foreground':1280,1831 'foreground-on':1279 'formal':1441,1454 'format':460,2000,2483,4152 'forward':86 'forward-look':85 'framework':551,2430,2951,3790,4664 'frida':932 'frida/objection':3336 'full':1998,4096,4228,4734 'function':678 'fundament':2383 'gap':277 'gate':236,240,430,795,920,1563,2558,3078,3306,3322,3990,4901 'gcm':26,1420,2173,2607,3006,3162,3639,4770 'generat':1966,2277,3290,3300,3364,3417,3425,3453,3477,3666,3873,4393,4662 'genericpassword':570,1885,1898,2106 'get':2407,4726 'goal':350,519,674 'govern':2452,4415 'ground':99,4474 'group':1984,1993,2226,2236,2656,2663,2666,4042 'guard':1977,3362,4922 'guid':153,199,203,696,759,1191,2355,4395,4647 'guidanc':88,664 'guidelin':720,857,3034,4637 'handl':330,960,1120,1758,1771,2088,2179,2516,2612,3589,3604,4237,4249,4407,4691,4886,4893 'handler':1243,1273,4330 'hardcod':423,1541,1548,1728,2439 'hardwar':801,1423,1433,2147,2571,3428 'hardware-back':800,1422,2146 'hash':807,1314,2032,2169,2603,4007 'heurist':2284 'hierarchi':2816 'high':478,1290,1576,1588,1614,1621,2112,2162,2181,2204,2254,4289 'high-valu':1289 'highest':1083,1209 'highest-secur':1208 'hkdf':1401,1417,1478,1608,1921,2613,3183,3537 'hkdf/pbkdf2':2180 'hmac':1330,2170,2604 'hookabl':3331 'hpke':30,814,1412,2190,2625,4197,4800 'hpke.recipient':4802 'hpke.sender':4801 'hybrid':1407,4201 'icloud':1299,2238,2669 'id':20,22,792,794,955,2228,2318,2658,2723 'id/touch':954 'identifi':276,278,537,685,4355 'ignor':432,875,1161,1573,1767,3059 'immedi':4301 'implement':128,262,310,670,724,735,867,2368,2871,3786,3829,4357 'implicit':1233,1585 'import':1964,2577,3409,3831,3852,4522 'improv':126,261,516,4359,4397 'includ':629,2056,4156,4190,4235,4276,4874,4912 'inclus':2487 'incorrect':3289 'incorrect/insecure':4162 'index':2073,4718 'info':1486 'info.plist':980,1726,2807,3093 'inform':4170,4373 'inherit':3891 'init':3432,3437,3463 'inlin':4195 'insecur':524,541,1509,1735,2755,2928 'insecure.md5':3191 'insecure.sha1':3193 'insid':1593,3426,3454 'instead':3297 'integr':753,2538,2905 'intent':247,3287 'intern':3489 'internetpassword':571,1883,2108 'interop':1387 'introduct':2402 'invari':3048 'invent':4354,4547 'investig':1693 'invis':3572 'invit':3654 'involv':763 'io':71,82,90,1034,1039,1177,1264,1312,1325,2063,2157,2191,2200,2500,2587,2626,2632,3501,3512,3763,3780,3806,3824,3834,3843,3854,3860,4183,4193,4198,4312,4319,4326,4672,4761,4775,4781,4793,4805,4808,4829,4847,4861,4944 'ios-on-mac':1176,2062 'ios/macos':8 'ipc':1019 'isavail':3373 'isol':2518 'issu':1986 'issuanc':2854 'item':302,378,786,1681,1819,1878,2527,3084,3884 'iter':1470 'jailbreak':2902 'januari':2437 'jwt':2853 'kem':33,1445,2195,2416,2594,2630,3517,3858,4812 'key':42,424,480,803,812,820,1172,1349,1361,1391,1399,1410,1430,1437,1462,1475,1476,1550,1598,1613,1723,1889,1914,1926,1958,2105,2150,2188,2212,2536,2618,2623,2643,2815,3163,3179,3411,3422,3450,3510,3683,3703,3895,4015,4029,4068,4204,4521,4931 'keychain':9,43,129,187,543,582,591,594,604,751,908,938,950,959,994,1015,1044,1132,1156,1715,1789,1800,1818,1850,1862,1931,1982,2051,2131,2232,2259,2300,2346,2365,2376,2506,2522,2526,2554,2584,2653,2661,2670,2686,2707,2747,2759,2802,2889,3083,3242,3460,3870,3881,3883,3956,4031,4034,4080,4230,4239,4510,4655,4678 'keychain-access-control.md':789,798,1086,1622,1841,2114,3125,3582,4073 'keychain-access-group':1981,2660 'keychain-bound':581,937,1788,2130,4229 'keychain-fundamentals.md':597,773,910,1046,1124,1183,1779,1871,2070,2081,3068,3115,3140,3150,3629,4000,4026,4039,4131,4402 'keychain-item-classes.md':574,782,1643,1662,1902,2098,2748,4063 'keychain-sharing.md':607,829,2014,2223,4037 'keychain/security':354,677,866 'keychainaccess':4571,4605 'know':4853 'ksecattraccess':1051,1581,1823,2543,3120,3547,3580,4267,4882 'ksecattraccessgroup':1996 'ksecattraccessibleafterfirstunlockthisdeviceon':1081 'ksecattraccessiblealway':1261,1618 'ksecattraccessiblealwaysthisdeviceon':1262 'ksecattraccessiblewhenpasscodesetthisdeviceon':1085 'ksecattraccessiblewhenunlock':1056,3561 'ksecattraccount':1901 'ksecattrkeytyp':1894 'ksecattrserv':1655 'ksecattrservic':1900 'ksecattrsynchroniz':1637 'ksecclass':13,779,1875,2101,3909,4062 'ksecclasscertif':2532 'ksecclassgenericpassword':1654,2529 'ksecclassident':2533 'ksecclassinternetpassword':2530 'ksecclasskey':1891,2531 'ksecusedataprotectionkeychain':1136,2057,3145,4831,4913 'lacontext':18,579,1560,2134,2553 'lacontext-on':578,1559 'lacontext.evaluatedpolicydomainstate':4850 'lacontext.evaluatepolicy':426,915,1803,3073,3301,4896 'later':1776 'launch':2265,2693,3869,3913 'layer':2829,2832 'leaf':609,2036 'leav':1432 'legaci':282,529,549,637,1152,1648,2689 'let':948 'level':218,223,275,367,1666 'librari':2948,2953,4569,4588 'libsodium':2944 'lifecycl':136,2210,2610,2641,4005 'line':2077,3943,4380 'link':3275 'list':3054,3208,4368 'load':291,303,384,544,553,564,573,585,596,606,613,699,764,2737,2835,2844,3921,3923,3936,3950,4113,4148,4346,4743 'locat':390 'logic':716 'logout':821,2219,2651 'look':87,2785 'loop':1595 'loss':4292 'lost':4537 'm1':454 'm1/m3/m9/m10':2319 'm10':457 'm3':455 'm9':456,1734 'mac':1173,1179,1329,2060,2065,2364 'maco':595,1134,1143,2047,2053,2093,2369,2501,2524,3148,3808,4832,4833,4838,4910 'main':3876,4908 'mainactor':1013,1848,3107,4906 'mainten':4620 'make':3569 'manag':137,170,2177,2814,3653 'mandat':68 'manual':165,1415,3645,3651 'map':142,448,1682,2286,2320,4094 'mastg':113,2316,2427,2720,2910 'masv':443,2314,2425,2718 'match':251,1064,1505,1825,2002 'materi':1928 'may':1062 'medium':479,1634,1642,1651,1661,2240,2269,2305,2323,4297 'memori':116,1934,3335 'mention':4145,4721,4753 'migrat':264,304,517,539,568,576,619,627,632,635,643,657,1199,1303,2260,2268,2684,2687,2696,4044,4051,4394 'migration-legacy-stores.md':545,559,841,1746,2256,3917,4047 'min':1311 'minimum':75,889,3925,4192,4251,4760,4849 'miss':295,3866,4526,4533,4652 'mistak':212,215,2279,2473,3265,3298,3356,3407,3467,3544,3584,3631,3693,3755,3864,4764 'misus':3743 'ml':32,1444,1457,2194,2415,2418,2593,2596,2629,3516,3520,3857,4811,4814 'ml-dsa':1456,2417,2595,3519,4813 'ml-kem':31,1443,2193,2414,2592,2628,3515,3856,4810 'mldsa65':1452 'mlkem768':1439 'mobil':1365,2310,2421,2714 'mobile-optim':1364 'mock':2294,2701,4085 'model':1067,3015,4598 'modern':79,268,518,4305 'modul':2153,2570 'move':3262 'mstg':2912 'mstg-resili':2911 'mtls':2251,2681,2739,2846,4056 'multipl':2997 'must':868,935,1255,3028,3423,4189,4275,4361,4472,4542,4560 'mutat':2303 'myapp':3878 'n/a':312,379 'name':4220 'nation':2443 'nativ':4563,4581,4599 'nearbi':1558 'need':1223,1269,1309,3929,4030,4178 'negat':1632 'negoti':864 'network':152,2823 'never':114,708,874,913,975,1009,1103,1116,1259,1356,1402,1431,1777,1909,1963,3027,3058,3071,3088,3103,3153,3169,3189,4147,4241,4332,4565,4680,4686 'new':676 'ni':1375 'non':49,863,1294,1773,2961,3481,3721,4261 'non-destruct':1772,4260 'non-exist':3480 'non-negoti':862 'non-opinion':48,2960 'non-uniform':3720 'nonc':1352,1358,1600,1908,2178,2611,3156,3635,3644,3652,3670,3686,4934 'note':1313,4309,4317,4381 'nsapptransportsecur':2808,3250 'nscode':983,1731,3096 'nsfileprotect':2124,2549 'nspinneddomain':2034,2248,2678,4856 'number':4338,4550,4973 'oauth':39,817,2855 'oauth2/oidc':2208,2639 'object':4593 'older':1376 'omit':3546,3674,4835 'on-devic':1967 'one':1684,2076,2978,3340,4379,4711,4729 'one-lin':2075,4378 'one-sent':4728 'opaqu':3442,3457 'open':3772 'open-sourc':3771 'openssl':2943 'oper':130,1060,1851,1938,3567,4012,4020,4679 'opinion':50,2962,4439 'opinion-seek':4438 'optim':1366 'option':2999 'order':4114 'organ':3021 'orphan':3897 'osstatus':14,433,876,882,1572,1752,2087,2515,3060,4236,4534 'out-of-scop':4421 'output':2482,3269,3707,4151,4242,4633,4676 'outsid':3229,4634 'overhead':4604 'owasp':112,442,852,1473,1733,2285,2309,2420,2713,2858,2909,4087 'owasp/audit':4143 'p256':1385,1428,1960,2149,2574,3001,3507,4771 'p256-only':2573 'p256.keyagreement':1393 'p256.signing':1381 'p256/curve25519':2621 'packag':3774,3819,3851,4798 'pair':2282,3288 'paramet':1487,3676,3687 'parenthet':4459 'parti':2870,2947,4568,4587,4619 'partial':4677 'pass':3647 'passcod':1206,1214 'passkey':2865,2874 'passkey/autofill':2743 'password':770,1461,3999 'patch':971 'patchabl':928 'path':3380 'pattern':59,97,305,322,395,398,405,475,494,530,620,707,1077,1096,1493,1503,1510,1520,1529,1828,2638,2711,2983,3041,3135,3203,3283,3294,3313,3343,3386,3452,3526,3577,3623,3628,3678,3745,3900,3973,4053,4111,4215,4219,4232,4477,4484,4709,4750,4959 'pay':415 'pbkdf2':1464,2614 'per':4463,4715 'perform':1390 'persist':1114,2154,2582,3456,3620,4032 'philosophi':47 'pin':610,612,832,2028,2038,2247,2677,2740,4055,4858 'pitfal':2386 'plaintext':987,1534,3664,3681 'platform':145,2353,2497,2941 'plist':839 'polici':2253,2683,2799,3571 'post':93,105,642,1435,1449,2160,2198,2381,2590,4817 'post-migr':641 'post-quantum':92,1434,1448,2159,2197,2589,4816 'potenti':1599 'pr':3811 'practic':65,534,2389,2435,2726 'pre':631,3500 'pre-io':3499 'pre-migr':630 'prefer':3051,4304 'prefix':2229,2659 'present':4592,4948 'previous':3447 'primari':2104,2329,2535,4067,4712 'primit':3524 'procedur':361,535,683 'produc':986,3308 'product':2432 'profil':2893 'project':440 'prompt':951 'proper':323,1893 'protect':593,1131,1168,2050,2122,2371,2521,2547,4072 'protocol':744,1942,2292,2699,4084,4705 'protocol-bas':743,1941,2291,2698 'provid':56,2856,3820 'provis':2892 'public':1409,2617,4203 'public-key':1408,2616,4202 'pure':4169 'purpos':3196 'push':1242,1272 'quantum':94,1436,1450,2161,2199,2411,2591,4818 'quantum-secur':2410 'queri':12,1147,2085,2512,3227,3933,3948,4121,4171,4425,4649 'question':4441 'queue':1859,3114 'quick':1185,1495,4455,4756 'quinn':106,2377 'race':1110,3616 'random':3669 'rapid':1674 'raw':1404,1609,3172,3696,3716,4924 'rawrepresent':3419,3433 'read':4258 'readabl':989 'readi':447,2322 'real':750 'reason':3953,4943 'recommend':80,4188,4629,4845,4952 'reconstruct':4749 'redirect':2757,2789,4722 'reduc':4608 'refer':123,159,227,231,292,313,332,387,469,481,624,654,702,766,1115,1186,1531,1687,1709,2072,2333,2351,2479,2809,3219,3255,3278,3478,3621,3919,4210,4347,4365,4370,4426,4442,4452,4456,4480,4557,4699,4704,4713,4717,4757,4953 'referenc':1523,4213 'references/biometric-authentication.md':587,797,973,1806,2129,3086,3355,3985,4225 'references/certificate-trust.md':615,836,1653,2045,2243,2742,4058 'references/common-anti-patterns.md':414,488,1007,1539,1553,1566,1578,1590,1604,1616,1741,1782,1808,2272,2761,2932,3044,3101,3167,3187,3200,3691,3753,3915,3959,3987,4093,4100,4125 'references/compliance-owasp-mapping.md':452,509,855,1749,2308,4091,4140 'references/credential-storage-patterns.md':548,776,823,1005,1745,2207,2751,3099,4003,4050 'references/cryptokit-public-key.md':558,566,816,1949,2184,3185,3751,4018 'references/cryptokit-symmetric.md':555,810,1947,2165,3165,3198,3543,3689,3863,4010 'references/keychain-access-control.md':790,799,1087,1623,1842,2115,3126,3583,4074 'references/keychain-fundamentals.md':598,774,911,1047,1125,1184,1780,1872,2071,2082,3069,3116,3141,3151,3630,4001,4027,4040,4132 'references/keychain-item-classes.md':575,783,1644,1663,1903,2099,2749,4064 'references/keychain-sharing.md':608,830,2015,2224,4038 'references/migration-legacy-stores.md':546,560,842,1747,2257,3918,4048 'references/secure-enclave.md':805,1636,1988,2145,3406,3466,3541,4025 'references/testing-security-code.md':667,742,849,1951,2290,4083 'refresh':1275,2214,2645 'regress':662 'reinstal':3889 'reject':4597 'relev':513,623,701 'reli':2869 'remov':1212,1215 'replac':837,1414 'report':459 'requir':441,1305,2484,3733,3833,4185 'resili':2913 'respect':1956,2952 'respons':4360,4375,4390,4417,4872 'restart':1239,1251 'restor':1257,3461 'restrict':1071 'retri':1775,4263 'retriev':3351 'return':880,900,922,1571,1759,1768,3063,3316,3374 'reus':1357,1601,1910,3154,3655,3658 'reveal':3659 'review':125,219,224,235,239,260,280,346,368,375,484,1498,1667,3575,3954,3977,4098,4400,4866 'review/audit':4128,4967 'right':3254 'risk':2079,2445,3995 'root':904 'rotat':2043,2216,2647 'round':1021 'round-trip':1020 'rout':1149,2095 'rsa':561,567 'rule':206,210,860,1266,2448,2956,3922,4153,4444 'run':272,363,646,726,1852,4868 'runtim':930,2217,2648,2896,2904,4518,4529,4536,4843 'safe':1201 'samkeychain':4572 'sanction':1000 'satisfi':869,1074 'save':3607 'say':4348,4488,4624 'scan':406,1496,3270 'schedul':4621 'scope':178,2466,2485,2732,2762,2780,2922,3230,4424,4427,4464 'score':376 'scratch':269,673 'se':1957,3421,3435,3449,3455,3472,3483,3487,3504,3528,4028,4520 'search':1500,1525 'secaccesscontrol':944,1799,2119,3348,4824 'secaccesscontrolcreatewithflag':2545 'secitem':11,878,1011,1140,1756,1845,2054,2083,2382,2385,3066,3105,4135,4403,4903 'secitemadd':1097,1118,1568,2508,3124,3136,3549,3587,4244,4272,4682,4878,4885 'secitemcopymatch':957,1557,2509,3353,4245,4688,4892 'secitemdelet':2511,3905 'secitemupd':1100,2510,3137,4889 'second':3606 'secondari':2343,4752 'secret':421,840,942,977,1211,1221,1229,1292,1406,1611,1712,1896,1917,2218,2649,2930,3090,3175,3346,3699,3718,4927 'section':341,569,577,600,628,2450,4367,4412 'sectrust':2244,2674 'sectrustevalu':1645,2027 'sectrustevaluateasyncwitherror':2023 'secur':3,34,36,44,158,164,358,550,639,715,846,964,1170,1210,1953,2261,2278,2354,2412,2433,2444,2498,2566,2688,2793,2824,2861,2897,3047,3195,3414,3570,3983,4022,4097,4295,4508,4663,4875,4915 'secure-enclave.md':804,1635,1987,2144,3405,3465,3540,4024 'secureenclav':2152 'secureenclave.aes':3470 'secureenclave.isavailable':1624,3359,3366,3400 'secureenclave.p256':2569,4777 'secureenclave.p256.signing':1426 'secureenclave.p256.signing.privatekey':3418 'securityd':1024 'see':4223 'seek':4440 'select':198,202,695,758,1190,1308,2203,2478,2635,2995,3011,4066 'self':234,238,4865 'self-review':233,4864 'self-review-g':237 'sensit':1084 'sentenc':4730 'separ':1490 'serial':1037,4322 'server':156,168,2796,2813,2848,2867 'server-manag':2812 'server-sid':155,2795,2847,2866 'servic':10,2347,2507 'session':110,2395,2405,4337,4549,4553,4972 'session/reference':4341 'set':784,1050,1135,1207,3119,3144,3579,3926,4069 'seven':859,2116,2542,3032 'sever':476,1530,2971,4283,4961 'sha':1471,2166,2600,3758,3777,3791,3821,3839,3845,4766,4783,4822 'sha256':1316 'sha3':1320,1322,3795,3797,3799,4785,4787,4789 'sha384':1317 'sha512':1318 'shape':4449 'share':603,824,1405,1610,1916,1990,2233,2654,3174,3698,3717,4033,4926 'sharedsecret':3726 'sharedsecret.hkdfderivedsymmetrickey':3749 'sharedsecret.withunsafebytes':1606 'sharedsecretfromkeyagr':3709 'show':4159,4681,4687 'shown':4960 'side':157,186,2495,2735,2797,2849,2868,2881,3241 'sidebar':2125 'sign':811,1379,1425,1451,2186,2620,2891,2900,3508,4013 'signal':3741 'signatur':1511 'signing/key':3530 'silent':897,1148,3376,3608,4290,4530 'simul':1628,1629,1979,2155,2295,2585,2702,3361,3370,3372,3383,3390,4501,4504,4921 'simulator-on':4500 'singl':601,3657 'skill':46,55,120,148,2462,2489,2773,2839,2877,2958,3237,4626 'skill-swift-security' 'skill.md':4410 'sole':428,3304 'somedata':3420 'sourc':1547,2325,2330,2344,3773,4222,4707 'source-dpearson2699' 'space':3334 'special':416 'specif':309,338,392,498,650,730,1697,3963,4117 'specifi':3633,4266 'specul':4150 'spki':2031 'spki/ca':611 'spki/ca/leaf':2246,2676 'stale':3892 'standalon':918,3076,4899 'standard':2863,3875 'start':343,485,682,1276,1282,4107 'state':464,3256,4282,4963 'step':636 'storag':38,525,542,1536,1737,2213,2637,2644,2745,2756,2831,2908 'store':283,940,976,1001,1929,2886,3089,3344,3996 'storing/reading':768 'strategi':2029,3019 'string':1543,1729 'struct':3877 'structur':4411 'style':3050 'suboptim':4298 'success':3317 'suffici':4461 'suggest':2782,2977,3259,3358,4491,4657 'summari':1702,4731 'support':2873,3221,3505,4701 'surviv':1195,1197,1256,3885 'sweep':1675 'swift':2,2301,2709,3769,3817,3849,4796,4839 'swift-crypto':3768,3816,3848,4795 'swift-secur':1 'swiftui':2915 'switch':886,1763 'symmetr':1398,1925,2581,2599,3178,3474,3484,3523,3702,4011,4930 'symmetrickey':1927,2176,2609,3534 'sync':1300,1646,2239,2671 'syncabl':1228,1836 'synchron':1861,2026 'system':1054,1230,2836,3559 'systemat':351 'tabl':228,232,1187 'tag':1355,3813,3838,4946 'take':3377,3705 'target':77,81,1128,1144,2048,3149,4052 'targetenviron':1627,3369,3389,4920 'task':259,690,762,1080,1241,1253,4136,4968 'team':2227,2657 'teamid.group.identifier':1999 'test':739,749,754,844,1945,2302,2304,2317,2697,2710,2722,3018,3384,4078,4503 'testing-security-code.md':666,741,848,1950,2289,4082 'thing':4469,4539 'third':2946,4567,4586,4618 'third-parti':2945,4566,4585,4617 'thisdeviceon':1295,1639 'thread':1029,4909 'threat':1066,3014 'throw/return':3392 'thumb':1268 'tier':2123,2548 'tighten':1285 'time':1337,3398,4516,4525 'tls':166,831,2798,2826,4054 'tn3137':599,2094,2362,2525 'token':40,772,818,1720,2209,2215,2640,2646,3893,3998 'token/key/secret/password':1533 'tone':2470,2955,2967,2973,3023,3211,3222,4435,4443,4591,4695 'top':217,222,274,366,1665,2273,2311,2422,2715 'top-level':216,273,365,1664 'top-level-review-checklist':221 'topic':2770,2786 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'total':3940 'touch':21,183,691,793,4103 'tradeoff':4594 'transport':163,2792,2828 'trap':1633,2156,2586 'tree':193,196,242 'trip':1022 'trivial':927 'true':1137,1638,2058,3146,4914 'trust':139,189,1649,2018,2252,2673,2682,4059 'tvos':2502 'type':540,1879,2102,3436,3794,3910,3949,4391 'ui':1865 'unclear':3017 'underpin':2331 'unencrypt':991 'uniform':3722 'uninstal':3887 'unit':748,1944 'unless':4937 'unlock':1205,1217,1227,1238,1250 'unsaf':3735 'unsupport':1162 'unverifi':4351 'updat':318,1095,2356,2390,3134,3627 'upgrad':520 'url':2834 'urlsess':2825 'use':4,663,692,781,883,914,1030,1090,1166,1202,1234,1260,1293,1384,1403,1485,1669,1700,1794,1882,1890,1897,1906,1923,1997,2022,2030,2460,2771,2975,3025,3072,3109,3129,3170,3190,3209,3296,3387,3469,3527,3586,3597,3682,3695,3711,3826,4021,4196,4431,4562,4670,4897,4928 'user':245,1515,3333,4576,4939 'user-spac':3332 'userdefault':419,838,979,1725,2919,3092,3903,4046 'userdefaults.standard.set':1532 'userdefaults/plist/nscoding':2258,2685 'userdefaults/plist/source':1717 'v2':2428,2721 'v2.0':2436 'v2.1.0':2315,2426,2719 'valet':4573,4607 'valid':633,2998 'valu':901,1291,1824,4883 'variant':1296 'verif':644,1442,1455,2862 'verifi':58,327,660,1333,4492 'version':226,230,2267,2695,3837,4163,4167,4184,4194,4447,4453,4754,4945 'version-reference-t':229 'via':931,1400,1465,1798,2583,3352,3462,3535,3714,3748,3782 'viewdidload':1867 'violat':1739 'visiono':2505 'vs':1830,1835,2107,2110,2234,2296,2372,2664,2703,2992,3002,3007,4433,4517 'vulner':2136,2559,4288 'warn':3215 'watch':1378 'watcho':2503 'web':1659,1880 'webauthn':2864 'whenpasscodesetthisdeviceon':1204,1287 'whenunlock':1226 'whenunlockedthisdeviceon':1216,1284 'window':1111,3617 'without':1119,1145,1372,1556,1569,1607,1625,3360,3367,3554,3588,3602,3684,3880,4247,4595,4645,4683,4689 'withunsafebyt':3715,3730 'work':6 'workaround':3736 'wrapper':2092,2917,2988 'write':843,4077 'wrong':289,467,1656,4294,4531,4654 'wwdc':109,2393,2403,4336,4548,4971 'wwdc25':3814 'xcconfig':981,1727,3094 'xkcp':3785 'xor':3661","prices":[{"id":"0dd519f9-f64f-40a9-b491-cddd0507f207","listingId":"0316da7c-299b-448e-867d-671919cc84fa","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-22T12:53:47.938Z"}],"sources":[{"listingId":"0316da7c-299b-448e-867d-671919cc84fa","source":"github","sourceId":"dpearson2699/swift-ios-skills/swift-security","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/swift-security","isPrimary":false,"firstSeenAt":"2026-04-22T12:53:47.938Z","lastSeenAt":"2026-05-18T18:53:45.167Z"},{"listingId":"0316da7c-299b-448e-867d-671919cc84fa","source":"skills_sh","sourceId":"dpearson2699/swift-ios-skills/swift-security","sourceUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swift-security","isPrimary":true,"firstSeenAt":"2026-05-07T20:41:53.331Z","lastSeenAt":"2026-05-07T22:41:16.147Z"}],"details":{"listingId":"0316da7c-299b-448e-867d-671919cc84fa","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"swift-security","github":{"repo":"dpearson2699/swift-ios-skills","stars":599,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-26T21:04:17Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"93eeffa4dea3853f9ecb50e4afe0a19cbbb39397","skill_md_path":"skills/swift-security/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/swift-security"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"swift-security","license":"MIT","description":"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 pinning (SecTrust, SPKI), keychain sharing across apps/extensions, migrating secrets from UserDefaults or plists, or OWASP MASVS/MASTG mobile compliance on Apple platforms."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/swift-security"},"updatedAt":"2026-05-18T18:53:45.167Z"}}