Skip to content

Security model ​

keymitt lets agents use credentials without the values entering their context. This page states precisely what that protects against — and what it does not.

What keymitt protects against ​

ThreatMitigation
A secret ends up in the agent's context, transcript or logsAgents only see {{secret:NAME}}. Everything returned — output, response headers and bodies, file contents, error messages — is redacted: the values of all secrets plus base64 (any alignment), URL-encoded (several styles), hex and JSON-escaped forms. When output is cut at a size limit, bytes that could start a secret cut off by the limit are dropped first, so no fragment is returned.
A secret is visible to other processesNever placed in command-line arguments. Temp files are owner-only, overwritten and deleted after the run.
A secret is used without you knowingEvery use needs approval through a prompt the agent cannot click. It names the secrets and the resolved program (or destination) first, then shows arguments, stdin, environment, temp files and directory — or method, URL, headers and the start of the body — with invisible characters escaped. Requests too long to show in full are refused.
A secret is handed to an impostor programPrograms are found only in absolute PATH directories; --command stores full paths.
A secret is sent somewhere it shouldn't bePer-secret allowlists of programs and hosts. http_request refuses placeholders and credentials in the URL, header injection, transport headers such as Host, non-HTTP(S) schemes and redirects, and ignores ~/.curlrc.
An allowed program is hijacked through its environmentVariables may only carry a secret, as exactly one placeholder, and never loader, interpreter, tool, proxy, CA or PATH-like variables. Policies can pin the allowed names.
A secret outlives the commandOn macOS and Linux each run's process group is killed when it ends.
read_file_redacted sidesteps your client's file rulesReads are confined to the workspace and configured roots; credential stores, key files, FIFOs and devices are refused.
Mass export of all secretsBackups and restores are CLI-only, need an interactive terminal, and always need strong approval.

What keymitt does not protect against ​

These follow from running as the same OS user as the agent.

  • A malicious agent with an unrestricted shell. It could bypass keymitt: read the Linux Secret Service or Windows Credential Manager directly (any process running as you can), edit policy.toml, or write a terminal-approval decision file. On macOS, another program reading keymitt's Keychain items triggers a system prompt — a higher bar, not a guarantee. Keep your client's own prompts for shell commands on.
  • What an approved program does with a secret. The arguments and stdin decide where it goes — both are in the prompt, so read it. Prefer http_request, which is host-restricted. Never allowlist shells or interpreters.
  • Programs that read configuration from the working directory, such as git with .git/config. The prompt shows the directory; be careful in untrusted repositories.
  • Weak approval methods confirm intent without authenticating you. Use allow_weak = false or method = "native" to forbid them.
  • The polkit dialog is generic; on Linux the details appear in a notification just before it.
  • Masking in read_file_redacted is not a boundary. A credential in an unusual format inside an allowed directory can still be shown; keep credential files out of the read roots.
  • Transformed values. A program that hashes, encrypts, reverses, wraps or splits a value defeats redaction.
  • Windows process trees. Only the direct child is stopped at the end of a run.
  • A compromised OS account or keychain.

Design decisions ​

  • The MCP server reads the policy once, at start-up, and never writes it. Agents have no tool to change the policy or the approval settings.
  • Approvals are not cached by default. With ttl_secs, only byte-identical requests to the same resolved program are remembered.
  • Cancelling an authenticating prompt denies the request; there is no retry with a weaker method.
  • Each decision records elapsed_ms, so an implausibly fast approval stands out in the audit log.
  • Inputs are bounded: arguments, stdin, each temp file and request bodies are limited to 1 MiB.
  • Values are read from the keychain per request and dropped afterwards. Rendered templates and backup plaintext use zeroizing buffers.
  • The testing build feature must never be enabled in builds that are installed or distributed.

Releases and installers ​

Release archives are built by GitHub Actions with pinned actions, read-only build tokens and no build cache. Each release carries SHA256SUMS.txt and signed build-provenance attestations (gh attestation verify <archive> --repo walisayu/keymitt). The one-line installers verify the checksum, refuse plain HTTP, check every archive path before extracting only the binary, and the shell installer runs nothing if its download is cut short.

Reporting a vulnerability ​

Please report vulnerabilities privately through GitHub security advisories, not in public issues.

Released under the MIT or Apache-2.0 license.