Skip to main content

Documentation Index

Fetch the complete documentation index at: https://theseventeen-2abbdf80.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Every read, write, delete, search, and rejected connection attempt is written to a local audit log in structured JSON format. The log gives you a precise, per-operation record of what accessed your keychain, when, and whether it was allowed — without ever writing the secret values themselves.

Where the audit log lives

PlatformDefault path
Linux~/.local/share/keychain-auth/audit.log
macOS~/Library/Logs/keychain-auth/audit.log
The log directory is created automatically by the daemon with permissions 0700. Only your user account can read it.

Log format

Each entry is a single JSON object on its own line (newline-delimited JSON). The file is append-only; new entries are added to the end as operations occur.

Fields

FieldTypeDescription
timestampstringISO 8601 UTC timestamp of when the operation was processed (nanosecond precision).
actionstringThe operation type: connect, read, write, delete, or search.
pidnumberThe kernel-verified process ID of the calling binary.
binary_pathstringAbsolute path of the calling binary on disk.
binary_hashstringSHA-256 hash of the calling binary, prefixed with sha256:.
servicestringThe keychain service namespace that was targeted (e.g. aws, AgentSecrets).
targetsarray of stringsThe key names that were requested. For search operations, these are the keys returned — never their values.
resultstringGRANTED, DENIED, or ERROR.
reasonstringPresent only when result is DENIED or ERROR. Explains why the operation was rejected.

Example log entries

A successful write followed by a successful read, then a denied attempt from an unregistered binary:
{"timestamp":"2026-05-21T01:00:15Z","action":"write","pid":8412,"binary_path":"/usr/local/bin/agentsecrets","binary_hash":"sha256:abcd1234...","service":"AgentSecrets","targets":["proj_123:development:DATABASE_URL"],"result":"GRANTED"}
{"timestamp":"2026-05-21T01:01:22Z","action":"read","pid":8412,"binary_path":"/usr/local/bin/agentsecrets","binary_hash":"sha256:abcd1234...","service":"AgentSecrets","targets":["proj_123:development:DATABASE_URL"],"result":"GRANTED"}
{"timestamp":"2026-05-21T01:02:40Z","action":"read","pid":9123,"binary_path":"/usr/bin/curl","binary_hash":"sha256:ff398bc...","service":"aws","targets":["default"],"result":"DENIED","reason":"unregistered_binary_pending_approval"}
Notice that the write entry at 01:00:15Z records the target key name — not the value that was stored. The read entry at 01:01:22Z records that the read was granted — not the secret that was returned.

Secrets are never written to the log

Plaintext secret values are never written to audit.log under any circumstances. The log records what was accessed and whether it was allowed — not what the secret contained.
This is a deliberate security boundary. Even if someone gains read access to your audit log file, they cannot harvest credentials from it. The log is useful for forensic investigation and anomaly detection without becoming a second place where your secrets are exposed.

Why search logs key names, not values

Search operations return a list of matching key names (targets) to the caller — never the corresponding secret values. The audit log reflects exactly what was returned: the key names only. This design limits blast radius. If a binary with search permission is compromised, an attacker can discover that a key named prod/stripe-key exists, but they cannot retrieve its value through a search alone. To read the actual secret, they need a separate read request — and that read generates its own audit log entry. This means the audit log captures granular, per-secret access records rather than opaque “search batch granted” entries. Each read for a specific key appears as a separate line in the log, making it straightforward to answer questions like “which process read my AWS production key at 3am?”
A search that found two keys logs the target names, not the values:
{"timestamp":"2026-05-21T02:10:00Z","action":"search","pid":8412,"binary_path":"/usr/local/bin/agentsecrets","binary_hash":"sha256:abcd1234...","service":"AgentSecrets","targets":["proj_123:production:DATABASE_URL","proj_123:production:STRIPE_KEY"],"result":"GRANTED"}
The subsequent reads each generate their own entry:
{"timestamp":"2026-05-21T02:10:01Z","action":"read","pid":8412,"binary_path":"/usr/local/bin/agentsecrets","binary_hash":"sha256:abcd1234...","service":"AgentSecrets","targets":["proj_123:production:DATABASE_URL"],"result":"GRANTED"}
{"timestamp":"2026-05-21T02:10:01Z","action":"read","pid":8412,"binary_path":"/usr/local/bin/agentsecrets","binary_hash":"sha256:abcd1234...","service":"AgentSecrets","targets":["proj_123:production:STRIPE_KEY"],"result":"GRANTED"}
When an unregistered binary attempts to connect, keychain-auth logs the rejection before closing the connection:
{"timestamp":"2026-05-21T03:45:12Z","action":"connect","pid":11204,"binary_path":"/tmp/malicious-script","binary_hash":"sha256:deadbeef...","result":"DENIED","reason":"unregistered_binary_pending_approval"}
The binary is also queued in ~/.config/keychain-auth/pending.json for your review.

Using the log for security monitoring

Because every entry includes binary_path, binary_hash, and pid, you can:
  • Detect unexpected binaries reading secrets they shouldn’t know about
  • Correlate access patterns with specific process IDs from your system logs
  • Confirm that a deployed binary’s hash matches the approved hash in your config
  • Identify DENIED entries that indicate active probing by unregistered processes
The log file is plain text and can be piped into any log aggregation or monitoring tool that supports newline-delimited JSON.