Operational security Independent guide
Hermes Agent security guide
Identify what a Hermes Agent deployment exposes, apply the controls that reduce it, and verify each control is actually in force.
A Hermes Agent deployment is as safe as four settings make it: which approval mode gates dangerous commands, which terminal backend executes them, where credentials live and what can read them, and whether anything is published on a network. Set those four deliberately, verify each one with an observable check, and treat every remaining control as defence in depth rather than a guarantee.
Checked against Hermes Agent v0.20.5 on . Re-check when approval modes, sandbox behaviour, gateway authorization defaults, or network controls change in a release.
Hermes Agent security baseline
Apply this before the agent touches anything that matters. Every item is verifiable.
- Keep the approval gate on.
approvals.modeatsmartormanual, neveroff, on any machine holding real data. - Choose the execution boundary consciously.
terminal.backend: localmeans the agent acts as you, on your machine. - Lock down secrets. Keys in
~/.hermes/.env,chmod 600on that file, nothing sensitive inconfig.yaml. - Publish no ports by default. The API server and dashboard stay unreachable until you deliberately expose them.
- Deny by default on messaging. No allowlist means every gateway user is denied — leave it that way until you add specific users.
- Constrain writes. Consider
HERMES_WRITE_SAFE_ROOTto confine file writes to one project prefix. - Keep it current. Track releases; security behaviour changes between them.
Threat model: what can act, access, and leave the machine
Think in terms of three questions rather than a list of scary words.
What can act? The model, driven by your prompt, by content it retrieves, and by any instructions inside skills or
context files. That is why untrusted content is an input to the threat model, not just a quality problem — prompt
injection is the mechanism, and Hermes Agent documents scanning of context files such as AGENTS.md, SOUL.md, and
.cursorrules for injection patterns and invisible Unicode.
What can it access? Whatever the enabled toolsets plus the terminal backend can reach: your filesystem, your shell, your network, and every service whose credential is present.
What can leave? Prompt content and tool output go to your model provider. Anything the agent can read, it can in principle include in a request or write to a tool call.
| Asset | Threat | Control | How to verify |
|---|---|---|---|
| Local filesystem and shell | A destructive or unintended command runs | approvals.mode at smart or manual; user deny rules under approvals.deny; a container backend where isolation matters | Ask the agent to run a command you expect to be blocked and confirm it is refused, not executed |
| Credential stores | Secrets are read or overwritten by the agent | Documented write protection for ~/.ssh/, ~/.aws/, ~/.kube/, auth.json, .env and project env files | Attempt a write to a protected path and confirm it is blocked |
| Provider and service keys | A key leaks into logs, a sandbox, or a subprocess | Keys only in .env with 0600 permissions; sandboxes do not inherit the host environment; MCP subprocesses receive only a safe baseline plus declared variables | Print the environment inside the sandbox and confirm no unexpected secret is present |
| Internal network and cloud metadata | A retrieved page steers the agent into requesting internal addresses | Private ranges, loopback, link-local, and cloud metadata endpoints are blocked unless security.allow_private_urls is enabled | Request an internal address and confirm it is refused |
| Messaging gateway | An unauthorised person sends the agent instructions | Explicit allowlists or DM pairing; default is deny when nothing is configured | Message the bot from an unapproved account and confirm no response or action |
| Dashboard and API server | An exposed endpoint gives full toolset access, including the terminal | API_SERVER_KEY is required for every deployment; the dashboard requires an authentication provider on non-loopback binds; prefer a tunnel over a published port | Request the endpoint without credentials and confirm rejection |
| Agent context | Injected instructions arrive inside retrieved content or a third-party skill | Context-file injection scanning; security scanning on hub-installed skills; explicit trust for project-local skills | Confirm a blocked file reports as blocked rather than loading silently |
Controls are documented in the Nous Research security guide, checked 25 August 2026 against v0.20.5. Verification steps are Applied Hermes recommendations.
Permission and approval modes
approvals.mode in config.yaml has three documented values:
smart(default). An auxiliary model assesses risk: low-risk commands are auto-approved, high-risk auto-denied, and uncertain cases escalate to you.manual. You are prompted for every command classified as dangerous.off. All approval checks are disabled — equivalent to--yolo.
Related keys matter as much as the mode itself. approvals.cron_mode decides what happens in scheduled runs where
nobody can answer a prompt, approvals.single_query_mode covers one-shot sessions, and approvals.deny takes your
own glob patterns, which are refused outright.
Two caveats that change how much comfort to take from this:
- YOLO mode is real and reachable. A flag, a slash command, or an environment variable can turn the checks off for a session. Treat its availability as part of your threat model on shared machines.
- A hardline blocklist always applies. Irreversible operations — recursive deletion of the root filesystem, fork bombs, formatting a mounted root, zeroing a device — are documented as blocked regardless of mode. That is a floor, not a safety net.
Recommended practice: run manual while you learn a new workflow, move to smart once you know what it
attempts, and never run off on a machine with credentials or production data.
Credentials and secrets
Documented behaviour:
- Secrets belong in
~/.hermes/.env; OAuth credentials are written to~/.hermes/auth.json. - Writes to OS credential stores and to Hermes' own secret files are blocked.
execute_codeblocks environment variables whose names contain secret-like words; the local terminal backend blocks Hermes infrastructure variables; the Docker backend passes no host environment by default; MCP subprocesses receive only a safe baseline unless you declare more.- Errors are redacted before reaching the model, replacing recognisable token patterns with
[REDACTED].
Recommended practice: scope every key at the issuing service, keep one key per purpose so revocation is cheap, rotate on a schedule you actually keep, and never paste a live key into a chat session or a shell command that lands in history.
Sandbox and terminal backends
The terminal backend is the single biggest lever on blast radius.
| Backend | Isolation | Dangerous-command check | Use when |
|---|---|---|---|
| local | None — runs as your user | Applied | You trust the task and need direct access to local files |
| ssh | A separate machine | Applied | Execution should happen somewhere other than your workstation |
| docker | Container | Skipped — the container is the boundary | You want a reusable, disposable execution environment |
| singularity | Container | Skipped | HPC environments |
| modal / daytona / vercel_sandbox | Cloud sandbox | Skipped | You want execution off your infrastructure entirely |
Source: Nous Research security documentation, checked 25 August 2026 against v0.20.5.
Documented container hardening includes dropping capabilities, no-new-privileges, a process limit, and sized tmpfs
mounts, with CPU, memory, and disk limits configurable under terminal:.
Browser/computer-use controls
Browser automation is the capability most likely to turn a page into an instruction. Documented controls:
- A configurable website blocklist under
security.website_blocklist. - SSRF protection that is always active for private ranges, loopback, link-local, CGNAT, and cloud metadata endpoints, with DNS failures failing closed and redirect chains re-validated.
security.allow_private_urls, default false, as the explicit opt-out.
The documentation is direct about what enabling that opt-out means: only do it where an agent following prompt-injected URLs into your local network is an acceptable risk.
Recommended practice: enable browser tools per task rather than globally, and never leave a privileged authenticated browser session available to an unattended agent.
Dashboard, gateway, and network exposure
Three distinct surfaces, each off or denied by default:
- API server. Exposes the full toolset including terminal commands.
API_SERVER_KEYis documented as required for every deployment, including a loopback bind. - Browser dashboard. Requires an authentication provider — basic auth, OAuth, or OIDC — on any non-loopback bind. There is no unauthenticated public-bind path.
- Messaging gateway. Denies every user when no allowlist and no allow-all flag exist. Pairing issues one-time codes with a documented expiry, rate limits, and lockout after repeated failures.
Recommended practice: prefer an SSH tunnel to a loopback bind over publishing a port. If you must publish, put authentication in front of it, restrict source addresses, and check the logs.
Skills and third-party integration trust
Skills and MCP servers introduce someone else's content and someone else's capability.
- Hub-installed skills are documented as passing a security scan for exfiltration, injection, destructive commands, and supply-chain signals; trust levels run from built-in through official, trusted registries, and community.
- Agent-authored skills can be gated with
skills.write_approvaland scanned withskills.guard_agent_created. - Project-local skills require explicit trust with
hermes skills trust. - A supply-chain advisory check flags known-compromised Python packages at startup and in
hermes doctor.
Recommended practice: read a community skill before installing it; a scanner reduces risk, it does not remove it.
Hosted deployment baseline
A deployment that stays on when you are not watching needs everything above plus five environment-level controls.
- Run as a non-root user, and never run the gateway as root.
- Use a container terminal backend so agent execution is not the host itself, with CPU, memory, and disk limits set.
- Publish nothing by default. Reach the dashboard through an SSH tunnel rather than a public port; if a port must be published, put authentication in front of it and restrict source addresses.
- One gateway per data directory. Two gateway processes against the same state is a documented way to corrupt it.
- Back up the state directory and test a restore. It holds credentials, so protect the backup as you would a password vault export.
The environment decision itself — local machine, a server you manage, or a managed backend — and the operations baseline that goes with it belong to secure a hosted deployment.
Apply this baseline to a hosted deploymentPrivacy and data-flow questions
Privacy is a data-flow question, and the answer is determined by your configuration rather than by a policy statement.
- Model provider. Hosted providers receive your prompts and tool output. Local endpoints do not.
- Hosted tool gateways. Search, image generation, speech, and browser services see the content you send them.
- Memory files.
MEMORY.mdandUSER.mdhold whatever the agent recorded about you. Inspect them; gate writes withmemory.write_approval: trueif that matters. - Sessions and logs. Session history and logs live in the Hermes home directory in plain files. Back them up accordingly and delete what you do not need.
We do not restate any provider's privacy policy here. Read the policy of the provider you actually configured, on the date you configure it.
Incident response and credential rotation
If you suspect the agent did something it should not have:
- Stop execution. Stop the gateway and any container running the agent.
- Preserve evidence. Copy
~/.hermes/logs/and the relevant session files before changing anything. - Rotate every credential the agent could read — provider keys, service tokens, anything in
.envorauth.json. Rotate at the issuing service, not just locally. - Establish reach. Which backend was active, which toolsets were enabled, was any port published, and which users could message the gateway.
- Restore from a known-good backup of the Hermes home directory rather than repairing in place.
- Re-enter with the gate on —
manualapprovals, minimal toolsets, no published ports.
Treat the rotation step as mandatory rather than precautionary: you usually cannot prove what an agent did or did not read, and rotation is cheap compared with the alternative.