Operations

Secret Handling

Protecting API keys, tokens, private files, and identifiers from accidental exposure.

Secret Handling

What it is

Protecting API keys, tokens, private files, and identifiers from accidental exposure.

In plain terms

Think of a public-records office fulfilling an open-records request: some file drawers are marked exempt and never even get pulled for review, while whatever documents do go out first get run through a redaction pass that blacks out anything shaped like an account number or password. Hermes applies the same two-step filter to itself: a short list of files it simply won’t open or overwrite, and a pass over anything it does read or save that blacks out text shaped like a key or token.

Why it matters

Keeping API keys, tokens, and other credentials out of a generated file, a tool call log, or a message sent to a model provider that doesn’t need to see them is what secret handling covers. The dashboard API’s credentials pool route exists specifically so secrets can be referenced by name rather than embedded directly in a skill, a cron job definition, or a prompt where they’d stay exposed to anyone reading it later. This gets especially important in gateway-connected mobile command center setups, where a credential mistakenly surfaced in a chat reply is visible on whatever device sits on the other end.

How it works

Two related denylists in agent/file_safety.py cover reads and writes separately. Reading is blocked for a fixed set of exact credential files, auth.json, auth.lock, .anthropic_oauth.json, .env, webhook_subscriptions.json, auth/google_oauth.json, plus anything under the mcp-tokens/ directory, and any project-local .env* file anywhere on disk, explicitly framed as defense-in-depth since the terminal tool can still cat these directly. Writing is blocked more broadly: on top of those same files, Hermes also refuses to write into ~/.ssh, ~/.aws, and ~/.gnupg, though those three directories are notably not on the read-denylist, so the agent’s read_file tool can still open an SSH key even though it can’t overwrite one. Separately, redact_sensitive_text (agent/redact.py) scrubs API-key patterns, auth headers, and connection strings out of file-read output and session transcripts before they’re persisted or shown. The dashboard’s credential-pool view (hermes_cli/web_server.py, via hermes_cli/config.py’s redact_key) applies the same head-and-tail masking, so a stored key only ever displays as a short preview, never the full value.

A concrete example

Asked to help debug a project, the agent tries to read its .env file directly; Hermes returns ‘Access denied’ and points to .env.example instead. Later the agent summarizes a log file that happens to contain a leaked Bearer token; the summary shows the token replaced with a masked placeholder rather than the raw string. On the dashboard’s credentials page, that same provider key, added earlier to a failover pool, shows up only as something like sk-p…9f2a, never in full.

How it connects

This note belongs to the Operations family. Its closest neighboring concepts are: Sandbox Boundaries, Source Evidence, Agent Runtime, Personal OS.

Source evidence

  • route:GET:/api/credentials/pool — Explicit Source Map scope boundary: The web server route is outside the approved Core scope.

Workflows

  • Gateway Mobile Command Center
  • How to Use Hermes Better Than Most People: Architecture, Project Isolation, and Scalable Workflows