Use GitHub's private vulnerability reporting for this repository: open the Security tab, then select Report a vulnerability. You can also open the private report form.
Please keep security reports private rather than opening a public issue or pull request. Include:
- The affected commit on
main, macOS version and relevant agent client/version. - A description of the security boundary that failed, the expected behavior and the potential impact.
- Minimal reproduction steps using synthetic credentials and isolated test data.
- Relevant, sanitized error messages or logs, with sensitive values and identifying details removed.
Never include real credentials, recovery material, vault contents or client configuration contents, even in a private report. Use synthetic replacements in examples and inspect attachments before submitting them.
Security reports are supported for the latest GitHub Release and main.
-
Credentials are encrypted locally. Agents request access through the restricted
askkeyhelper and the App's local Broker. Allow, Ask (the default) and Hidden are credential-wide permissions; Allow still requires Broker-mediated delivery. -
AskKey's management, MCP and helper responses do not return stored credential plaintext. Approved text values go to the selected target process; file values use short-lived private files. An approved target can print, copy or forward the material it receives.
-
Caller-provided names, paths, signatures and purposes are display context, not verified identity or authorization. A timed read allowance applies globally to one credential or an explicitly approved group snapshot for the local macOS user; it does not isolate one agent client from other programs running as that user. A group snapshot lists visible, unexpired credentials outside the Recycle Bin, bound by ID and component-metadata digest; later additions are excluded. Its shared deadline is capped by the earliest member expiry. A member's metadata, permission or group change removes that member; explicit revocation from any member ends the whole grant. Expiry, revoke-all and pause end every member together, as do screen lock, sleep and user switch once this process adopts the enabled End Timed Allow on Lock setting. Writes always require separate approval.
-
The End Timed Allow on Lock setting in Settings is off by default and requires ownership and system authentication to change in either direction. Once this process adopts it as enabled, screen lock, sleep and user switch revoke all single and group timed grants, unconsumed timed approvals and prepared timed runtime authorizations. Sleep starts at willSleep; user switch is session resign. A remote opt-in not yet adopted is checked at the next ending event through a Keychain policy read (which can fail) or at the next agent request. New timed grants are refused while locked, asleep or switched out; an unknown screen state also blocks them. An unlocked sample cannot clear willSleep until clock bounds prove real sleep, unless didWake is received. Aborted sleep without didWake keeps new timed grants blocked until didWake, unless a later unlocked sample proves a subsequent real sleep (fail-closed). Waking does not override a switched-out session. Allow credentials, once-only approvals, pending requests and management sessions retain their existing behavior, except a prepared run that also contains a timed credential is cancelled as a whole. Turning the setting off does not revive revoked authority.
-
AskKey does not guarantee that another process running as the same macOS user cannot inspect or copy material after approved delivery. Hidden excludes a credential from the Agent catalog and access requests, but does not defend against same-user side channels.
-
Approval is bound to the requested operation and frozen payload. Agent writes require a separate approval and commit the frozen content atomically; approval cannot be reused for a different operation or changed payload.
-
Revocation, expiry and pause prevent delivery that has not passed the final launch authorization check and trigger temporary-file cleanup. They cannot retract material already received by a target. Agent access can be paused while management is locked or closed. After the existing system confirmation, Pause first cancels requests and approvals and cleans up deliveries locally, regardless of policy-writing ownership; a non-owner reports an unsaved pause. Resuming access requires valid ownership and system authentication and does not unlock management.
-
One Ask Key process serves each library namespace. Before opening the vault, the App holds a private exclusive file lock for its lifetime; another launch requests activation of the running instance and exits, reporting a lock error or an unanswered activation request. Development and production libraries have separate locks. Broker startup holds a separate short file lock around probing the socket, removing a stale path, binding and listening. A successful connection probe refuses startup; shutdown only closes the descriptor and leaves the path for the next startup. This is best-effort protection: a same-user process can remove lock files or replace paths, a non-cooperating server can bind outside the startup lock, and a live listener with a full backlog may refuse connections.
-
Agent-access policy changes take effect across processes at the next agent request. Catalog requests, approval decisions (also after system authentication), agent commits and the final delivery/spawn boundary re-read and verify the Keychain policy. The stricter persisted or in-memory policy wins: either pause blocks access, either authentication requirement is enforced, either disabled timed allowance disables it, and the shorter duration applies. Adopting a stricter policy written elsewhere cancels requests and approvals and cleans up deliveries. The user's own settings changes preserve pending and once-approved requests and delivered files; disabling timed allowance revokes timed windows and their runtime authorizations, while once-only authorizations remain valid unless their prepared run also contains a timed credential, in which case the entire run is cancelled. Read authentication applies to future decisions, and timed decisions are capped by the current default duration. Denial requires neither policy I/O nor the agent-access gate and preserves an existing cancellation. Cross-process writes are not serialized. Only the Broker owner writes persisted policy; Resume and relaxing settings require valid ownership. A non-owner can Pause or tighten some settings locally, with a persistent unsaved-change notice; changing End Timed Allow on Lock requires ownership in both directions. Before each write, the owner re-reads policy under its in-process exclusive gate and checks the socket path's device and inode against the identity recorded at bind. Connection acceptance, subsequent requests and final authorization also check ownership. A removed or replaced path, including a link to the old socket, revokes the grant and stops this instance's listener; the access gate stays paused, outstanding work is quiesced and the UI reports that this instance has stopped serving the library. Retry can bind a fresh socket and regain ownership, while authenticated Resume is still required to lift the local pause. Only authenticated Resume may lower
paused. These path checks are best-effort: a same-user process can replace a path after it was checked, so they do not provide atomic cross-process write serialization. -
The agent-access policy (pause, read-approval authentication and timed-allowance settings) lives in the fixed login keychain file under the same App-only access control as the vault key and is authenticated with the App key. Vault, pending, legacy and policy operations are pinned to that file, independently of the default keychain or search-list preferences; duplicate or outside-keychain items are rejected. Each policy save deletes the previous item, adds a fresh App-only item and verifies its value. An interrupted replacement can leave the policy missing.
-
Without an App key, AskKey discards any existing pending key and generates a new key; a library whose contents exactly match first creation is discarded and recreated, unless this Vault still holds its open store. While no App key exists and the library has no credential rows (before first creation, after a local erase, or after an interrupted creation), a same-user process that plants an App key, alone or together with an empty supported library, can choose the key.
-
A confirmed missing, invalid or conflicting policy pauses agent access, requires read-approval authentication and disables timed allowances until system-authenticated resume restores defaults. A transient unreadable policy refuses access and pauses this process without latching recovery or replacing the user's settings; later requests retry the read. If the policy item exists and access is rejected while the pinned keychain is unlocked, the UI directs the user to review that item's access control without deleting vault keys. A Pause during an unreadable read or after ownership loss latches the unsaved pause and reports that it was not saved, even when no policy read has succeeded yet; local cancellation and file cleanup still take effect. Runtime policy changes and ownership revocation notify the UI. Verified first creation under the lifetime library lock initializes defaults after key promotion without requiring a running Broker; an existing library with an App key fails closed even when it has no credential rows. Libraries predating this policy take the recovery path once after updating. A failed pause, settings or Resume save keeps agent access paused in this process with a persistent notice that distinguishes an unchanged policy from an unknown persisted state. Locally tightened, unsaved settings remain restrictive on reopening. Reopening retries a pending pause save only for the owner when a valid policy was loaded and recovery has never been latched in this process; recovery prevents all retry writes. Reopening cannot clear pause intent or recovery; only a successfully saved, system-authenticated Resume clears these latches. An unsaved pause may be lost when the App restarts. Successful authenticated local erase resets the latches for a new library.
-
The component-metadata completion marker uses HMAC-SHA256 with a vault-key-derived HKDF key and a separate authentication domain. A valid development-only v1 encrypted marker is replaced atomically on open; a missing, invalid or mixed-version marker pauses Agent access while keeping management available. The marker does not authenticate other config values or prevent whole-library rollback.
-
Replacing the whole library database with an older copy is not detected, an existing credential-history rollback limitation; this includes restoring the completion marker together with the data, or restoring a pre-metadata snapshot that is backfilled again. The current policy remains in the Keychain. Replacing the whole login keychain file is not detected either. An older signed Ask Key build that can read the vault key is not bound by this policy.
-
Update checks (ADR 0011) are the App's only outbound network requests, and only the official Release install at
/Applications/Ask Key.appmakes them. A check requestshttps://askkey.sudohg.com/appcast.xml, which Cloudflare redirects to the appcast attached to the latest GitHub Release; updates download from GitHub Releases. Both hosts see the IP address, theUser-AgentAsk Key/<version> Sparkle/<version>and the standard headers macOS adds, including preferred languages, and cookies they set are stored for Ask Key. No system profile is sent. The appcast and the update archive must carry valid EdDSA signatures from the public key built into the App, so neither host is trusted for integrity; this does not protect against a compromised signing key or a release the maintainer publishes. Sparkle offers only newer versions, and every install needs the user's confirmation. The relaunch waits while an approval prompt is waiting, an approved request is unused, a Broker call is running, an upload is open or an authentication prompt is showing; a relaunch then locks management and ends timed allowances.
The feature inventory records the retained behaviors and planned removals during restructuring. Report a suspected violation of these boundaries privately, including when the observed behavior differs from that inventory.