Local-First Secrets for AI Agents on macOS: A 2026 Field Survey

A field survey of local secret stores for AI agents on macOS—and the privilege boundary needed to keep an agent from erasing its own access trail.

en

What exists today for storing and brokering credentials—strings and files—entirely on one Mac, consumable by coding agents unattended, with an access trail that the agent’s own user account cannot directly rewrite. Claims from my hands-on testing are labeled as such.

This survey is the technical companion to I Didn’t Know Where My Keys Had Leaked, So I Started Building GuestSafe. The other article tells the personal story and describes the narrow tool I decided to build; this one preserves the broader product research and security reasoning behind that decision.

TL;DR

I wanted my Claude Code agents to use credentials (Gmail service accounts, API keys, SSH keys) that never leave my machine, work without human prompts, and leave a local access trail. I surveyed six categories of tooling—server-style secrets managers, password-manager vaults, developer secret injectors, agent-era credential brokers, MCP secrets servers, and macOS primitives—against four criteria plus one extra lens I care about: the home-vault standard. It is acceptable that malicious code running as my login account can use a credential already delegated to that account, but it should not be able to rewrite the record of that use.

That last sentence needs a precise threat model. Here, “same-user attacker” means an unprivileged process running as my login account. It does not include root, Recovery Mode, physical destruction, or an administrator who can reconfigure the logging system. Under that model, the useful boundary is privilege separation: the agent can request a secret, while a different service identity owns the audit trail.

Three conclusions:

  1. Most local vaults and injectors do not record secret reads. Some commercial products reserve audit features for paid tiers; some “activity logs” record changes rather than reads.
  2. OpenBao is the closest documented fit. Its audit devices record requests and responses (with documented exceptions), but a file owned by the agent’s own account is not a security boundary. Run the daemon or its audit sink under a different service identity if the log must survive compromise of the agent account.
  3. No single macOS primitive is a permanent, unerasable ledger. Unified-log entries rotate, sappnd is reversible by root, and EndpointSecurity products still need protected log storage. The practical local design is privilege separation plus bounded retention; a durable external anchor is stronger but no longer “one Mac only.”

中文摘要

我调研了 macOS 上为 AI agent 提供“纯本地、支持文件凭证、无人值守、记录读取行为”的六类工具。关键结论不是某个文件标志能让日志永久不可删,而是权限分离:agent 可以读取已授权的凭证,但审计日志应由另一个服务身份拥有。OpenBao 是目前最接近这套需求的通用工具;统一日志、sappnd 和 EndpointSecurity 可以加固方案,但都不是永久、绝对不可擦除的账本。若把哈希锚点复制到机器之外,证据会更强,但也不再满足“只在一台 Mac 上”的严格定义。

The requirements

Four requirements surround a local Mac: local custody, file credentials, unattended access, and an access audit

My constraints, in order of non-negotiability:

  • C1 — Local custody. No vendor cloud. A localhost-only daemon is fine; SaaS is not.
  • C2 — File credentials. A secret is an arbitrary byte blob — a GCP service-account JSON, an OAuth client secret file, a PEM key — not just an env-var string. Plain .env doesn’t cover this.
  • C3 — Unattended. Agents fetch secrets with zero human prompts. macOS Keychain can do this for items whose access control already trusts the calling application, but that choice trades prompts for a broader standing authorization.
  • C4 — Access audit. A local record of who/what read which secret, when.

Plus the lens that reframes C4: tamper resistance against the agent account. A log file owned by my login account can be erased by malicious code running as that account—they hold the same pen. The practical question is therefore: can the agent cause an auditable operation while a different identity owns the resulting record?

Master table

Here, C4 means that the product documents a record of secret reads or API requests. It does not mean the record is tamper-resistant; that depends on who owns the logger and its storage. A dash means the tool is out of scope for the criterion, while “not verified” means I did not find sufficiently specific public documentation.

ToolC1 LocalC2 FilesC3 UnattendedC4 AuditStatus 2026
OpenBao⚠️ base64 KV✅ API request/response audit, freeactive (Linux Foundation)
Vault⚠️ base64 KV✅ per-requestBUSL license
Infisical self-hosted⚠️ local, heavy⚠️ values/base64❌ enterprise paywallactive
Conjur OSS⚠️ values❌ officially Enterprise-onlymaintained, heavyweight
Keywhizdead (archived 2023)
KeePassXC✅ attachments⚠️ password/key file❌ no per-read log documentedactive
Vaultwarden + bw✅ attachments⚠️ org events onlyactive
1Password❌ cloud only✅ documents⚠️ cloud-sideno local mode
Psono⚠️ not verified⚠️ EE tieractive
Passbolt CE❌ no per-read log documentedactive
pass / gopass✅ gopass❌ no read log documentedactive
macOS Keychain (CLI)⚠️ generic-password data; CLI caveats✅ with pre-authorized ACL❌ no supported per-item read log foundusable with tradeoffs
sops + age✅ structured/binary modes❌ no read log documentedactive
SecretSpec✅ provider choice⚠️ not verified✅ local access logyoung (2025)
novops✅ via sops✅ in-mem files❌ no read log documentedactive
dotenvx⚠️ env values❌ no read log documentedactive
fnox⚠️ not verified⚠️ not verifiednew, active
vals✅ sops/keychain❌ values only❌ no read log documentedactive
envchain✅ keychain❌ no read log documentedfrozen 2024
aws-vault❌ AWS only❌ no read log documentedabandoned; fork alive
teller⚠️ dotenv only❌ no read log documentedsemi-dormant
chamber❌ AWS⚠️ CloudTrailactive
Pomerium✅ self-hostable❌ tokens✅ request logactive

A. Server-style secrets managers

An agent sends secret requests to a local service while a separate identity owns the audit ledger

OpenBao is a fork of Vault managed under the Linux Foundation and is MPL-2.0 licensed. It has the best-documented free audit path in this survey: an audit device records requests and responses for nearly every API operation, including errors, with a short list of unaudited system paths. Most sensitive strings are salted HMAC-SHA256 values rather than plaintext. Auditing is off on a newly initialized server and must be enabled by an OpenBao root-policy user. OpenBao supports file, socket, syslog, and HTTP audit devices and recommends enabling more than one. It also offers a filesystem storage backend, although the project warns that this backend is not recommended for production because it is non-transactional and lacks system-level file locking.

Two operational gotchas matter on a Mac. Since OpenBao 2.4, declarative self-initialization and audit-device configuration remove some manual setup, but fully unattended self-initialization still requires Auto Unseal. The Homebrew formula installs the bao binary, while the tempting bao server -dev path stores data in memory and loses it on restart. A durable deployment still needs a real seal, storage, identity, listener, policy, audit, backup, and upgrade plan. More importantly, a file audit device inherits the protection of its host account. If OpenBao and the agent both run as my login user, malicious code can remove the file. If OpenBao or a local audit collector runs as a dedicated service identity and its directory is not writable by my login user, the same agent token can fetch secrets without gaining the ability to rewrite the log. That privilege boundary, not the file format, provides the useful protection.

Vault itself has the same audit capability but has been Business Source License 1.1 since August 2023 (v1.15.0 and later, each release converting to MPL 2.0 four years out), and HashiCorp is now IBM, which completed the $6.4 billion acquisition in February 2025. OpenBao is the open path to the same architecture.

Infisical self-hosted (my incumbent, via its cloud) runs as the app plus PostgreSQL plus Redis, minimum 2 CPU / 4 GB RAM. The core repo is MIT except the ee directory of enterprise features. The dealbreaker: audit logs are a paid feature — self-hosters are told to contact sales to purchase an enterprise license to use them.

Conjur OSS is still maintained (v1.24.0 in November 2025) and offers policy-as-code, but CyberArk staff state that audit logging is officially supported only in Conjur Enterprise. That removes it from C4 and leaves a PostgreSQL-backed, enterprise-shaped system for a single Mac. Keywhiz is deprecated and no longer maintained; Square points users to Vault.

B. Password-manager vaults with CLIs

A local password vault can hold strings and files, but opening it does not necessarily create a read ledger

KeePassXC is the simplest fully local vault in the set: a single KDBX file, with real file-credential support via keepassxc-cliattachment-export writes an attachment to a specified file. Unattended use can supply a password on standard input or use a key file with the CLI’s --key-file and --no-password options; either way, the automation still needs custody of unlocking material. Its Secret Service integration acts as a Secret Service provider over D-Bus, a freedesktop.org facility rather than a macOS Keychain interface. I found no documented per-entry read log.

Vaultwarden — the unofficial Bitwarden-compatible server written in Rust, AGPL-3.0 — gives genuinely local custody with the official bw CLI, which supports unattended auth via API key and --passwordenv / --passwordfile unlock. Audit is the weak leg: Bitwarden event logs are records that capture changes and usage across your Teams or Enterprise organization — organization-scoped, so your own personal-vault reads aren’t meaningfully covered. In Vaultwarden, org events are only stored in the database — the maintainer explicitly declined file/SIEM output. And the bws Secrets Manager won’t work against Vaultwarden: that feature is Bitwarden-licensed, not open-source licensed; self-hosting it officially requires an enterprise plan.

1Password—evaluated honestly since I already use it for browser autofill—has no current standalone-vault mode. 1Password 8 requires a 1Password membership; the same page says 1Password 7 and earlier supported standalone vaults. The self-hostable Connect server caches data in your infrastructure but syncs with 1password.com, so it reduces runtime cloud dependence rather than providing local custody. Credit where due: the Environments MCP server exposes variable names but not secret values and injects values into an authorized process via a local in-memory FIFO. It is not unattended in the sense used here: the current walkthrough says every interaction requires explicit user approval.

Psono has an automation CLI (psonoci, built for CI), but its audit log is only available in the Enterprise Edition. General encrypted file attachments remain listed as a Passbolt feature request, and its paid activity log is described as auditing changes, not as a per-secret read ledger. pass/gopass are fully local, and gopass supports binary files through the cat, fscopy, fsmove, and sum subcommands, but Git history records writes, not decryptions. Gopass’s audit command checks passwords for common flaws; it is a password-quality audit, not access logging.

C. Developer secret-injection tools

A trusted injector supplies credentials directly to an authorized process while the agent handles only names and operations

SecretSpec (announced in July 2025 by the devenv/Cachix team) is the standout design. A committed secretspec.toml declares what secrets an application needs while values live in a pluggable provider, including Keyring, KeePass KDBX, pass/gopass, age, 1Password, OpenBao, and others. It is the only injector in this survey whose public documentation advertises built-in access auditing: every secret access is recorded locally, auditing is on by default, and values are not logged. It is still young, and I have not verified arbitrary file-credential materialization.

novops (LGPL-3.0) has the best file-credential ergonomics: its config materializes secrets as in-memory files with an environment variable pointing at the path—exactly the GOOGLE_APPLICATION_CREDENTIALS pattern—with SOPS among its local-capable sources. Its documentation does not advertise a per-read audit log.

dotenvx, from the creator of dotenv, encrypts .env files with ECIES; each secret uses a unique ephemeral key, while you keep the private key in a gitignored .env.keys. Its documentation does not advertise a read audit. fnox, from mise author jdx, manages secrets with encryption or cloud providers, including age, OS Keychain, KeePass, and password-store providers. Mise’s secrets documentation recommends fnox over its experimental SOPS/age integration. vals resolves ref+backend:// references with local backends including SOPS and files, plus a macOS Keychain backend.

The older generation: envchain stores env vars in macOS Keychain or D-Bus secret service but hasn’t had a commit since its April 2024 release. aws-vault’s README states the project has been abandoned, with a maintained fork at ByteNess — AWS-only either way. chamber stores secrets in SSM Parameter Store — AWS-coupled, no local backend. teller’s last release was v2.0.7 in May 2024.

Among the injector documentation I checked, SecretSpec is the only project that explicitly promises a local access record. Absence from documentation is not proof that no debug or system log exists; it means I would not select the tool to satisfy C4 without testing and a documented retention contract.

D. Agent-era credential brokers and MCP

An agent invokes a brokered tool while the credential remains outside model context

The new product category built around agents needing credentials is mostly SaaS; managed-auth products therefore fail C1 by design. The self-hostable exception in this survey is Pomerium, an identity-aware proxy that manages upstream OAuth and injects the token into proxied requests without exposing it to clients. It supports service accounts for autonomous agents and logs every tool call with the method, tool name, and parameters. Architecturally, that is useful, but it brokers API calls rather than materializing file credentials and adds another resident service.

An MCP tool that returns raw secret values is usually the wrong boundary. HashiCorp ships an official Vault MCP server (public beta since HashiConf 2025) whose tools include reading and writing secrets in KV mounts. In an ordinary MCP client, the result of a read tool can enter the model-visible transcript; that is an architectural inference, not a claim that every client stores every result. Frank Denis’s critique captures the principle: the model does not need the token. GitGuardian reported 24,008 unique secrets in MCP-related configuration files on public GitHub, including 2,117 valid credentials, while OWASP’s MCP Top 10 begins with token mismanagement and notes that developers put credentials in configuration files, environment variables, prompt templates, and model context. The safer pattern is to let the agent name an operation or variable while a trusted process injects the value outside model context.

Claude Code itself ships relevant primitives. On macOS, its own authentication credentials are stored in the encrypted macOS Keychain, and an apiKeyHelper can return an API key at runtime. For sandboxed Bash commands, credential deny mode removes named environment variables and blocks configured files. Environment-variable mask mode (v2.1.199+) gives the command a per-session sentinel and substitutes the real value only through the sandbox proxy; this requires TLS termination and a trusted user, managed, or command-line settings source. The proxy can re-sign detected AWS SigV4 requests. File masking (v2.1.221+) is platform-dependent: Linux and WSL2 receive a sentinel copy, while macOS blocks reads instead of substituting. An exact filesystem.denyRead rule also holds inside a wider allow. These controls reduce exposure; they do not provide a secret store or a durable read audit by themselves.

E. OS primitives: where a harder-to-erase trace can come from

A macOS audit trail combines bounded local logs, append flags, monitoring, and a protected sink

The home-vault requirement cannot be met by a log file owned by the compromised account. macOS offers useful building blocks, but none is an infinite, unerasable ledger. Their value is relative to the stated attacker: an unprivileged process running as the agent’s login account.

PrimitiveWhat it givesLimitationCost
uappnd flagappend-only file; blocks overwrite/deleteowner, silently (chflags nouappnd)free — guardrail only
hash-chained loginternal consistency; edits detectable if head is knownowner, by rewriting the whole chainfree — needs an anchor
unified log (os_log)centrally stored records a normal user cannot directly editentries rotate; administrators can manage or erase the storetiny
sappnd flagappend-only flag set and cleared only by rootroot can clear it; not permanent immutabilityneeds root
Santa FAAlogs or blocks watched file access by process identitydurability depends on protected telemetry storage and administrationroot, FDA, system-extension approval
eslogger / FileMonitorEndpointSecurity stream of file eventsa stream is not durable until written to a protected sinkroot/FDA requirements vary by tool
external copy of a chain headdetects later local rewriting if the external copy is trustworthyviolates the strict “one Mac only” constraintoperational dependency

The receipts:

  • Keychain is a store, not the read ledger I need. A 2017 investigation found that useful information about keychain opens had largely vanished from the unified log, and I found no current Apple interface promising a per-item read audit. This does not make unattended use impossible: the installed security manual says an item can trust a specific application with -T, or every application with the explicitly discouraged -A, so the correct table entry is “usable with ACL tradeoffs,” not “always prompts.” The classic BSM audit subsystem is deprecated since macOS 11 and disabled since macOS 14, with Apple pointing developers to EndpointSecurity. I also reproduced a narrower CLI problem: the interactive security -i path is reported to have a 4,096-byte input-line limit. In my test on macOS 26.4.1, 100 KB and 400 KB blobs round-tripped when passed as hex through an argument, so this is an interactive-input limitation, not evidence of a small Keychain item limit.
  • Unified logging is a useful short-lived anchor, not immutable storage. On my machine, BSD logger messages did not appear in the queries I tried, while a small compiled os_log call produced entries retrievable with log show. Apple says the unified system centralizes logs in memory and on disk, but also documents that entries rotate according to space, time, and classification. The log tool also has an erase command. A normal user cannot edit a stored entry in place, which is useful against the agent account, but retention is bounded and an administrator remains stronger than the log.
  • BSD file flags are guardrails with explicit owners. In my test, uappnd allowed append while blocking overwrite and removal, but the owner could clear it. Apple’s file-system guide confirms that uappnd is owner-or-root controlled, while sappnd is root-only. The earlier claim that sappnd requires Recovery Mode to clear was wrong: Apple documents that root can change it.
  • EndpointSecurity monitoring is practical, but the sink still matters. eslogger ships with macOS and must run as superuser with Full Disk Access, though its manual says it is not intended as an application API. Objective-See’s FileMonitor outputs JSON from the same framework. The purpose-built option is Santa: File Access Authorization can monitor, log, or block access, and its events identify the time, process, path, and decision. Santa can send telemetry to the unified log or to files, so its resistance to deletion depends on the selected sink and who administers the system extension.
  • FileVault is baseline protection for data at rest. Apple says the disk is decrypted after an authorized user logs in, so FileVault helps against offline theft but not malicious code already executing in that logged-in session. The Secure Enclave is also reachable from the age ecosystem through age-plugin-se, which supports access-control policies from none (automatable and hardware-bound) through current-biometry and requires macOS 14 plus a Secure Enclave for key generation and decryption.

What the survey shows

  1. Read auditing is unusual in lightweight local tools. SecretSpec documents it; OpenBao documents API-level auditing; several commercial systems reserve it for paid tiers; many “activity logs” track changes rather than reads.
  2. OpenBao is the strongest single product in this survey. It can meet C1–C4 on one Mac, but the home-vault property comes only when the agent account cannot administer the daemon or its audit sink.
  3. Tamper resistance is a deployment property, not a checkbox. A dedicated service identity and a root-owned or otherwise protected sink create a meaningful boundary against an unprivileged agent process. Unified logging, Santa, and hash chaining can strengthen that design, but none promises permanent local retention.
  4. The safer agent pattern is capability use without value disclosure. Secret names and intended operations may enter model context; raw values should be injected into a narrowly authorized process or proxied request. 1Password Environments, Pomerium’s upstream-token injection, and Claude Code’s mask mode are variations on that idea.
  5. Watch list: SecretSpec for declarative access records and fnox for local encryption in the mise ecosystem. SecretSpec’s log still needs the same privilege-separation treatment if it must survive compromise of the agent account.

What this led me to build

The survey convinced me that OpenBao is the strongest general-purpose answer, but it also clarified the mismatch. Its complexity buys high availability, dynamic secrets, leases, PKI, and infrastructure-scale lifecycle management. My local agents need a much narrower path: discover a small catalog, request a named credential with context, inject it into one process, and record every result.

That is the space I want GuestSafe to occupy. It is not a smaller OpenBao. It is a good-enough, lightweight, auditable replacement for .env.local, with a deliberately limited threat model and a much smaller operating surface.

Methodology

The survey combines public product documentation with hands-on tests on my Apple-silicon Mac running macOS 26.4.1: Keychain CLI input paths, chflags semantics, BSD logger versus os_log, and the current BSM manual. Inline links point to the specific capability being discussed; text-fragment links (#:~:text=) highlight the supporting passage where practical. Product documentation is sufficient evidence for a documented interface or edition boundary, but not for an absolute claim that no undocumented behavior exists. I therefore use “not verified” for gaps, label local tests and architectural inferences, and avoid treating a vendor’s feature ranking as an independent comparison.

Sources and further reading

Server-style managers

Password-manager vaults

Injectors

Agent-era & MCP

macOS primitives

© 2026 Zainan Victor Zhou. All rights reserved.

v2.1.1 · cda9c0 · 2026-08-18 19:53 UTC