| Version | Supported |
|---|---|
| 1.2.x | Yes |
| 1.1.x | Yes |
| 1.0.x | No |
If you discover a security vulnerability in PassStore, please report it responsibly.
Do not open a public GitHub issue for security vulnerabilities.
Instead, email feedback@makio.app with:
- A description of the vulnerability
- Steps to reproduce the issue
- Any potential impact assessment
You should receive a response within 48 hours. We will work with you to understand and address the issue before any public disclosure.
The canonical user-facing security write-up (threat model, session, clipboard, updates) is passstore.makio.app/security. The bullets below are the in-repo technical summary aligned with the source.
Cryptography (at rest)
- Vault payload: AES-256-GCM (Apple CryptoKit). Vault snapshot is JSON, then encrypted with a random 256-bit vault key.
- Password → vault key: Argon2id via libsodium (swift-sodium): 16-byte salt, opsLimit
3, memLimit 256 MiB. Legacy vaults use PBKDF2-HMAC-SHA256 (600 000 iterations); on first successful unlock they are re-wrapped with Argon2id automatically. - No custom ciphers.
Key hierarchy (short)
- Master password never encrypts item data directly: KDF → derived key → AES-GCM unwraps a random vault key → that key AES-GCM-encrypts the vault JSON.
On-disk artifacts
vault.package: authoritative atomic package containing the wrapped vault key metadata and encrypted vault envelope.vault.meta/vault.enc: owner-only compatibility mirrors for older PassStore versions; current builds never fall back to them whilevault.packageexists, even if the package is corrupt.vault.rollback: owner-only atomic recovery package created before a destructive restore. The vault and rollback settings remain AES-256-GCM encrypted; pre-release 1.2 rollback files with legacy plaintext settings are read only for recovery and are never newly written.- Custom tag and environment ordering is stored inside the encrypted vault, not in
UserDefaults; plaintext keys written by pre-release 1.2 builds are migrated and removed after a successful unlock.
Encrypted backup (.pstore)
- Format v3: random export key encrypts the backup JSON; your export password wraps that key using the same Argon2id + AES-GCM pattern as the live vault (
ExportServiceinVaultTransfer.swift).
Keychain and Touch ID
- When biometric unlock is enabled, a copy of the vault key is stored in the macOS Keychain with
kSecAttrAccessibleWhenUnlockedThisDeviceOnlyandbiometryCurrentSet(LocalAuthentication). If biometrics are disabled, that Keychain item is removed.
On disk
- Default location:
~/Library/Application Support/app.makio.PassStore/(or the app bundle id), directory0700; vault, compatibility mirrors and rollback files are0600and use atomic replacement.
Previous values (1.2.0)
- Replacing a secret keeps the value it replaced, capped at 10 versions per field, inside the same encrypted payload as everything else. This is opt-out (Settings → Data), purgeable per item and vault-wide, and cleared from memory on lock along with the live values. It does mean a rotated secret stays recoverable from the vault until purged — rotate and purge if a value was leaked.
Linked files (1.2.0)
- An item may store an app-scoped security bookmark to the
.envit mirrors. The bookmark grants PassStore access to that one file. PassStore reads linked files when you open their status or bring the app to the front (if the setting is enabled), and releases access immediately afterwards. It writes only after you press Write and confirm any conflict; no file is watched continuously. Generated values are quoted and shell expansion characters are escaped before writing.
Global shortcut
- ⌘⌥P is registered with the window server (
RegisterEventHotKey). PassStore does not request Accessibility permission and does not observe keystrokes outside its own windows. Before 1.2.0 it installed a globalNSEventmonitor, which required Accessibility and delivered every keystroke from every application to the app.
Memory
- Password bytes used in Argon2id and PBKDF2 paths are zeroed after derivation where the code controls the buffer; the in-memory vault key, all decrypted item/workspace/template strings, private sidebar metadata, previous values, decrypted import previews and undo snapshots are cleared on lock. Swift
Stringpasswords cannot be reliably zeroed (platform limitation).
Network
- Vault operations do not transmit vault data. Direct-download builds may use Sparkle to fetch an update feed (see
Info.plist); that is unrelated to encrypting or syncing secrets.
Code references
| Area | File |
|---|---|
| Encryption, KDF, vault files | PassStore/Data/Security/VaultPersistence.swift |
| Session, auto-lock, clipboard | PassStore/Data/Security/VaultSecurity.swift |
| Keychain vault key | PassStore/Data/Storage/SecretStores.swift |
.pstore export/import |
PassStore/Data/ImportExport/VaultTransfer.swift |