To harden Hermes Agent, install a pinned stable release after reading the installer, move command execution off your host into the Docker or SSH backend, keep provider keys out of the sandbox, and put the agent behind a default-deny egress proxy. Then switch on skills.write_approval and memory.write_approval so every skill and memory the agent writes waits for your review.
Hermes Agent is the open source, MIT licensed agent from Nous Research that keeps memory, writes its own skills and can run on a server that you message from chat apps. That last part is why hardening matters: an agent that runs shell commands, reads the open web and edits its own procedures is a program whose behaviour can be steered by text it reads. Hermes's own security policy says so plainly, and the project ships good controls. Most of them are off by default or only protect you when you pick the right backend. This guide walks through each control from the Hermes docs, with the real config.yaml keys, and ends with a complete hardened configuration you can adapt.
Every version number, default and config key below was checked on 23 October 2026 against the Hermes docs, the repository at the v0.22.5 tag and the GitHub releases API. Hermes ships several releases a week, so check the linked pages again before you copy anything into production.
Key takeaways
- Hermes's security policy states that "the only security boundary against an adversarial LLM is the operating system." Approval prompts, redaction and scanners are useful heuristics, not containment.
- The default terminal backend is
local, which runs commands on your host with no isolation. Usedockerorsshfor anything that reads untrusted content or accepts messages from other people. - A terminal sandbox only confines shell and file tools. Code execution, MCP subprocesses, plugins, hooks and skill loading still run in the agent's own process, so the strongest posture wraps the whole agent in a container with restricted networking.
docker_forward_envis empty by default. Keep it that way, and use the Hermes egress credential proxy so the sandbox only ever holds stand-in tokens.- Skill and memory writes are ungated by default (
skills.write_approval: false,memory.write_approval: false). Turn both on and keep agent-created skills in a git repository so every change has a diff. - Approvals default to
smart, where an auxiliary model approves low-risk commands for you. On a work machine, setapprovals.mode: manualand add your ownapprovals.denyrules, which hold even under--yolo. - Install from the stable channel, pin a release commit or image digest, and run
hermes update --checkandhermes doctorbefore and after every upgrade.
What you are hardening: Hermes Agent in one paragraph
Hermes Agent is a single-user agent harness. You install it on a laptop, a workstation, a server or in a container, connect it to a model provider of your choice, and talk to it from a terminal UI, a desktop app or a messaging gateway (Telegram, Discord, Slack, email and many more). It has tools for shell commands, file edits, web search and extraction, a browser, code execution and MCP servers. It keeps two small memory files and a searchable session history, and it writes reusable procedures called skills into ~/.hermes/skills/ after it works something out. On 23 October 2026 the GitHub API reported about 256,000 stars for the repository, a dated snapshot of interest rather than a measure of safety or deployment.
Release timeline relevant to hardening
Dates below come from the release notes' own "Release Date" line where one exists, with the GitHub publication time in UTC noted when it differs. The launch date comes from nousresearch.com/releases, not from the repository creation date.
| Date | Version | What changed for security and operations |
|---|---|---|
| 22 Jul 2025 | (repository created) | Pre-public foundation work begins (GitHub API created_at) |
| 25 Feb 2026 | Public launch | Listed on nousresearch.com/releases as an agent that "lives on your server" |
| 12 Mar 2026 | v0.2.0 | First tagged release after the pre-public v0.1.0 foundation |
| 7 May 2026 | v0.13.0 "Tenacity" | Named release in the CalVer tag series |
| 28 May 2026 | v0.15.0 "Velocity" | Named release; v0.15.1 patch followed on 29 May |
| 5 Jun 2026 | v0.16.0 "Surface" | Desktop app and web dashboard (published 6 Jun UTC) |
| 1 Jul 2026 | v0.18.0 "Judgment" | Self-verification and /learn, which turns sources into skills |
| 20 Jul 2026 | v0.19.0 "Quicksilver" | Smart approvals become the default; user-defined deny rules; pluggable secret sources for password manager integrations. The notes say the egress proxy was reverted in this window |
| 3 Sep 2026 | (CVE records) | Two CVE records for Hermes Agent published on CVE.org (see below) |
| 8 Oct 2026 | v0.21.6 | First SemVer tag through the new stable release gate; dashboard sign-in hardening and automatic git operations skip repository filter programs |
| 13 Oct 2026 | v0.22.0 "Threshold" | Tested stable channels, signed desktop packages and MSIX, a signed Termux APT repository, the security.allow_lazy_installs switch, opt-in per-profile plugin host, approvals.deny enforced inside sandboxes (published 14 Oct UTC) |
| 22 Oct 2026 | v0.22.5 | Latest stable at the time of writing, release commit bf0203a794a; Docker stable tag points at it (published 23 Oct UTC) |
Two CVE records exist for the project, and both are useful context for the controls below. CVE-2026-71963 describes command execution through a crafted git core.fsmonitor setting in a repository opened by Hermes Agent 0.18.2 through 0.21.0, which is a reminder to treat any cloned repository as untrusted input. CVE-2026-85105 records an authorization bypass in session management reported against version 0.18.0, which is a reminder to keep the gateway off the open internet and keep the install current.
The threat model in Hermes's own words
Before touching a config file, read section 2 of the project's SECURITY.md. It defines input surfaces (anything that enters the model's context: web fetches, email, gateway messages, file reads, MCP responses, tool results) and the "trust envelope", which is everything your user account can reach when you run the agent. Then it draws one line: "The only security boundary against an adversarial LLM is the operating system." The approval gate, output redaction, pattern scanners and tool allowlists are all described as heuristics. Shell is Turing-complete, so a denylist over command strings can never be complete, and the approval gate "catches cooperative-mode mistakes, not adversarial output."
The policy describes two isolation postures, and choosing between them is the most important hardening decision you will make:
- Terminal-backend isolation. A non-default backend runs model-emitted shell commands, and the file tools built on them, inside a container, a remote host or a cloud sandbox. This confines shell and file operations. It does not confine code execution (spawned as a host subprocess), MCP subprocesses, plugin loading, hook dispatch or skill loading, which all run in or from the agent's own Python process.
- Whole-process wrapping. The entire agent process tree runs inside a sandbox, so every code path is subject to the same filesystem, network and process policy. The policy names Hermes's own Docker image and Compose setup as the lighter way to do this, plus a third-party per-session sandbox runtime. It calls this "the supported posture" when the agent ingests content you do not control (the open web, inbound email, multi-user channels, untrusted MCP servers) and for production or shared deployments.
The policy is equally plain about what falls outside its support: running the default local backend with untrusted input surfaces, or expecting a terminal sandbox to contain code paths that do not go through the shell. If you remember one thing from this post, make it that sentence.
This maps cleanly onto the OWASP Top 10 for LLM Applications 2025 entry LLM06, Excessive Agency, which OWASP describes as the vulnerability "that enables damaging actions to be performed in response to unexpected, ambiguous or manipulated outputs from an LLM", with root causes of excessive functionality, excessive permissions and excessive autonomy. Every control below reduces one of those three. For the general theory of agent sandboxes, our posts on sandboxing an AI agent that runs shell commands and guardrails versus sandboxes go further; this post sticks to Hermes configuration.
Threat and control mapping
| Threat | What it looks like in Hermes | Primary control | Backup control | Default on 23 Oct 2026 |
|---|---|---|---|---|
| Destructive or unwanted shell command | Model runs a command that deletes, overwrites or reconfigures | Container or SSH terminal backend | approvals.mode: manual, approvals.deny, checkpoints | Backend local, approvals smart, checkpoints off |
| Credential theft from the sandbox | Injected instruction reads environment variables or token files | Empty docker_forward_env, egress credential proxy | Env filtering for subprocesses, output redaction | Forwarding empty, proxy off, redaction on |
| Data exfiltration over the network | Command posts files or secrets to an outside host | Whole-process container on an internal network with an allowlisting proxy | SSRF guard, website blocklist, content-level curl checks | Container networking is host mode in the default Compose file; SSRF guard on |
| Strangers driving your agent | Someone messages the gateway bot | Platform allowlists or DM pairing | unauthorized_dm_behavior: ignore | Deny all unless allowlisted; pairing replies on chat DMs |
| Poisoned skill or memory that persists | A bad lesson or injected procedure is saved and reused in later sessions | skills.write_approval, memory.write_approval, git-tracked skills | skills.guard_agent_created scanner | Both gates off; guard off |
| Untrusted repository content | Project skills, context files or git config in a cloned repo | hermes skills trust only for repos you control; current release | Scan-time quarantine, context file injection scanner | Project skills not loaded until trusted |
| Third-party code in the agent process | Plugins, hooks, Skills Hub installs, lazy dependency installs | Review before install, pin refs, plugins.isolation: host | security.allow_lazy_installs: false, hermes skills audit | Plugins disabled until enabled; lazy installs on |
| MCP server misuse | A server receives secrets or asks the agent's model for text | Explicit env per server, tools.include, sampling off | Credential redaction in MCP errors | Env filtered; sampling on |
| Stale, vulnerable install | Known bugs stay in place | Stable channel, hermes update --check, pinned digest | Built-in advisory check in hermes doctor | Stable channel for new installs |
1. How do you install Hermes Agent without piping a script blind?
The quick start on the installation page is a one-liner that pipes install.sh from hermes-agent.nousresearch.com into bash (PowerShell irm and iex on native Windows). It works, but you run a 1,300 line script you have not read with your user's full privileges. There are better routes, and which one you take depends on the platform.
Option A: read the source installer, then run it pinned
The installer is a normal shell script. Download it, read it, record its hash in your change log and run it with explicit flags. On 23 October 2026 the script accepted --channel stable|main, --commit SHA, --branch NAME, --dir PATH, --hermes-home PATH, --non-interactive, --skip-browser, --skip-computer-use and --include-desktop.
# 1. Download to a file instead of piping into a shell
mkdir -p ~/hermes-install && cd ~/hermes-install
curl -fsSL https://hermes-agent.nousresearch.com/install.sh -o install.sh
# 2. Read it. Look at what it downloads, where it writes and what it runs as root.
less install.sh
grep -n 'sudo\|curl\|https://' install.sh | less
# 3. Record a hash so you can tell later whether the script you ran has changed
shasum -a 256 install.sh | tee install.sh.sha256
# 4. Find the commit behind the stable tag you intend to run
git ls-remote --tags https://github.com/NousResearch/hermes-agent.git 'v0.22.5^{}'
# 5. Run it pinned, without the browser and computer-use drivers if you do not need them
bash install.sh --channel stable --commit <release-commit-sha> \
--skip-browser --skip-computer-use --non-interactive
On 23 October 2026 the dereferenced v0.22.5 tag pointed at commit bf0203a794a07aac3ff764972ab9087baa4e4f4e, which matches the "measured at commit" line in the v0.22.5 release notes. We did not find a published checksum or signature for install.sh itself, which is why step 3 records your own hash. The script does verify its own downloads: it fetches a pinned build of the uv Python tool and checks it against a SHA-256 value baked into the script, and the docs say managed tool archives are pinned by version and SHA-256 in pm/lock.json.
--skip-browser and --skip-computer-use matter for hardening. By default the installer adds a pinned Chromium and a computer-use driver; if your agent does not need to drive a browser or your desktop, leaving them out removes two large capabilities, and hermes update will not add them back. On glibc Linux the installer may also run your package manager as root or via sudo -n to add libatomic, so for a service account the docs recommend that an administrator installs system prerequisites first and the installer then runs as the service user.
Option B: signed desktop packages
Since v0.22.0 the desktop app ships as a signed package with its own Python and Node: a signed MSIX bundle (or Microsoft Store package) on Windows, and a DMG for Apple Silicon Macs. Package-owned installs update through their own updater, and the docs warn against running git or pip inside a signed app.
Option C: the Docker image, pinned by digest
The Docker image is the simplest route to whole-process wrapping, covered under question 5. The Docker docs page lists three tag families: latest and stable (the image accepted by the stable release gate), main (development builds) and versioned stable images. It says to use a digest for an exact pin. On Docker Hub on 23 October 2026 the versioned tag was v0.22.5, with a leading v, while the docs table writes the pattern as X.Y.Z. Check the tag list before you script it.
docker pull nousresearch/hermes-agent:v0.22.5
docker image inspect nousresearch/hermes-agent:v0.22.5 \
--format '{{index .RepoDigests 0}}'
# Use the printed name@sha256:... reference in your Compose file
Option D: Android through the signed Termux repository
The Termux route uses a signed APT repository. The docs tell you to download the public key, check its fingerprint with gpg --show-keys --with-fingerprint, and stop if it does not match the fingerprint printed on the page. They also carried a warning on 23 October 2026 that the Termux package "does not work right now" with a fix in progress, so this is not yet a route for production use.
After any install
Run the diagnostics before you connect any credentials:
hermes --version
hermes doctor # config, dependencies, storage, install provenance, advisories
hermes update --check # compares with the selected channel without applying anything
hermes doctor also surfaces Hermes's built-in supply chain advisory check, which compares installed Python packages against a curated catalog of known-compromised versions and prints remediation steps. Read any advisory before you acknowledge it with hermes doctor --ack <advisory-id>.
2. Which terminal backend should you choose?
The terminal backend decides where model-written commands run. The security page's comparison table lists local, ssh, docker, a Singularity plugin for HPC, and three hosted cloud sandbox backends. Note that the backend count differs between pages: the security page table has seven rows, while the work-machine guide shows only local, docker and ssh. We used the security page.
| Backend | Where commands run | Dangerous-command check | Good fit | Poor fit |
|---|---|---|---|---|
local (default) | Your host, as your user | Yes | A trusted user, trusted inputs, a throwaway machine | Any gateway, any untrusted web or email content, any machine with production credentials |
ssh | A separate machine you control | Yes | Keeping the gateway and the execution host apart | Cases where the remote host also holds sensitive data |
docker | A hardened container on your host | Skipped; the container is the boundary | A personal or work machine, a production gateway | Workloads that need host devices or host credentials |
| Singularity plugin | A container on HPC systems | Skipped | Shared research clusters | Desktops |
| Hosted cloud sandbox backends | A provider's sandbox or microVM | Skipped | Scalable or disposable execution | Data that must not leave your environment |
Why local is the wrong default for a gateway
With the local backend, a command the model writes runs on your machine as you. The only things between a manipulated model and your files are the approval gate and the file-write denylist, and Hermes's own docs say both are guardrails "against an honest-but-wrong agent" rather than a sandbox. The file-write guards apply to write_file and patch only; the terminal tool runs as the same OS user and "can still cat or overwrite denied paths via shell commands."
A messaging gateway multiplies the problem: anyone who can message the bot, and anything it reads (a pasted link, an email it triages, a page it summarises), can steer which commands get proposed. The production checklist says to use a container backend.
So the rule of thumb is short. Use local only for yourself, on content you trust, on a machine you could rebuild. Use docker everywhere else, ssh when you want execution on a different host, and wrap the whole agent (question 5) when the agent reads the open web, inbound mail or group chats.
3. How do you configure the Docker backend safely?
The Docker backend runs every terminal command inside one persistent sandbox container per Hermes process. The security docs list the flags Hermes applies to every such container:
--cap-drop ALL, then a minimal add-back ofDAC_OVERRIDE,CHOWNandFOWNERso package managers can work.SETUIDandSETGIDare added only when the image starts as root and must drop privileges.--security-opt no-new-privileges. Docker's run reference describes this option as disabling container processes "from gaining new privileges", which stopssu,sudoand setuid binaries from raising privileges.--pids-limit 256to cap process count.- A size-limited
/tmp(512 MB,nosuid) and anoexec/var/tmp(256 MB).
Those defaults are good. Your job is to avoid weakening them and to tune the rest.
# ~/.hermes/config.yaml
terminal:
backend: docker
docker_image: "nousresearch/hermes-sandbox:desktop" # default sandbox image at v0.22.5
docker_forward_env: [] # default; keep it empty
env_passthrough: [] # nothing extra reaches terminal or execute_code children
container_cpu: 1 # default 1 core
container_memory: 4096 # MB; default is 5120
container_persistent: false # default is true; false uses tmpfs and discards on cleanup
Choosing persistence
With container_persistent: true, the default, Hermes bind-mounts /workspace and /root from ~/.hermes/sandboxes/docker/<task_id>/ so files survive across sessions. That is convenient, and it also means anything a bad command drops into /root (a shell profile, a cached credential, a modified tool) is still there next time. With false, the workspace lives on tmpfs and is lost on cleanup. For a gateway that reads untrusted content, prefer ephemeral containers and move durable outputs out deliberately.
Pinning the sandbox image
The default sandbox image at v0.22.5 is nousresearch/hermes-sandbox:desktop, which became the default in v0.22.0. A mutable tag can change under you. Pull it, record its digest, and set docker_image to the digest reference. If you build your own sandbox image, base it on a pinned digest, install only the tools the agent needs, and run as a non-root user so the conditional SETUID and SETGID add-back is skipped.
Host-side Docker hygiene
The container is only as strong as the Docker daemon behind it. The Docker security docs and NIST SP 800-190 both stress patching the host and daemon and limiting who can reach the Docker socket; Docker's rootless mode narrows the blast radius further. Never mount your home directory, your SSH directory or the Docker socket into the sandbox to make a task easier.
4. How do you keep secrets out of the agent's reach?
Hermes has several overlapping mechanisms for credentials. They are worth understanding together, because the gaps between them are where keys leak.
Where secrets live
Provider keys and gateway tokens live in ~/.hermes/.env, not in config.yaml. The security docs recommend chmod 600 ~/.hermes/.env and never committing it. Since v0.19.0 Hermes can also fetch secrets at load time from password manager integrations through a pluggable secret source interface, so keys need not sit in a plaintext file at all. Since v0.22.0, hermes config get masks secrets unless you pass --raw.
chmod 700 ~/.hermes
chmod 600 ~/.hermes/.env
ls -la ~/.hermes/.env
What subprocesses can see
The docs describe the default filtering per sandbox:
| Child process | Default filter | How variables get through |
|---|---|---|
execute_code | Blocks names containing KEY, TOKEN, SECRET, PASSWORD, CREDENTIAL, PASSWD or AUTH, and only allows safe-prefix variables | Skill-declared variables and terminal.env_passthrough |
terminal with local | Blocks Hermes infrastructure variables (provider keys, gateway tokens, tool keys) | Same passthrough lists |
terminal with docker | No host variables at all | Passthrough lists plus docker_forward_env |
terminal with ssh | No host variables | Passthrough via SendEnv, which needs a matching AcceptEnv on the server |
| MCP stdio servers | Only PATH, HOME, USER, LANG, LC_ALL, TERM, SHELL, TMPDIR and XDG_* | The server's own env block in config |
Two of these deserve attention. First, a skill can declare required_environment_variables in its frontmatter, and when the skill loads, any of those variables that are set are passed through automatically, including into Docker containers. That is convenient for a weather API key. It also means a skill you did not write can widen what the sandbox sees, which is one more reason to review skills before installing them (question 8). Second, if you add names to docker_forward_env, the docs warn that code in the container "can read and exfiltrate them."
Keep real keys out of the sandbox entirely
The cleanest answer for the Docker backend is the egress credential proxy, which Hermes manages with hermes egress. It runs a pinned, SHA-256 verified open source TLS-intercepting proxy on the host. The sandbox gets the usual provider variable names set to opaque proxy tokens, plus a local CA so its HTTP clients trust the proxy. The proxy swaps each token for the real key on the way out, but only for upstream hosts on its allowlist. If the sandbox is compromised, the attacker holds tokens that only work through your proxy. Our post on the credential proxy pattern covers the general idea.
hermes egress install # downloads the pinned proxy binary
hermes egress setup # creates the local CA, mints proxy tokens, writes proxy.yaml
hermes egress start
hermes egress status
proxy:
enabled: true # default false
enforce_on_docker: true # default true: refuse to start a sandbox if the proxy is down
credential_source: env
upstream_deny_cidrs: null # null keeps the safe default deny list
extra_allowed_hosts: [] # add only the extra hosts you need
Know the documented limits. The proxy covers the Docker backend only; SSH and the hosted backends do not get it yet. The host process's own model calls still use your .env keys directly, because the threat model is the sandbox. The guarantee depends on the proxy's CA private key and endpoint staying trustworthy. And v0.19.0's release notes say an earlier version of this proxy was reverted in that window; on 23 October 2026 the proxy section is present in the v0.22.5 defaults and on the current docs site.
Borrowed logins and imported secrets
auth.adopt_external_logins defaults to true, which lets Hermes read and refresh login files that other coding CLIs on the machine store when it has no login of its own. On a hardened install, give Hermes its own login and set it to false. The importer for other agents never reads credential files and strips secret-looking MCP variables, with one exception: OpenClaw API keys and bot tokens come over with --migrate-secrets, which first-run setup passes for OpenClaw imports. Re-enter keys by hand so you know exactly which credentials the agent holds.
5. How do you restrict network egress?
Hermes has three network controls inside the agent and one documented pattern outside it. You want the outside one for any gateway.
Inside the agent: SSRF guard, private URL policy and website blocklist
All URL-capable tools validate destinations before fetching. The SSRF guard blocks RFC 1918 private ranges, loopback, link-local (including the cloud metadata address 169.254.169.254), the RFC 6598 shared range and metadata hostnames, treats DNS failures as blocked, and re-checks every redirect hop. Leave security.allow_private_urls at its default of false on anything internet-facing; the docs call turning it on "a deliberate trust boundary."
The website blocklist adds your own domains and applies to web search, web extract, the browser and other URL-capable tools:
security:
allow_private_urls: false
website_blocklist:
enabled: true # default false
domains:
- "*.internal.example.com"
- "admin.example.com"
shared_files:
- "/etc/hermes/blocked-sites.txt"
The dangerous-command detector also flags curl or wget requests whose bodies carry a secret-named variable or a credential file, and commands containing invisible or bidirectional Unicode. Those go through approval like other flagged commands.
These controls govern Hermes's own tools. They do not stop a shell command from opening a raw socket. That is a job for the network.
Outside the agent: default-deny egress around the container
The Hermes docs page "Network Egress Isolation (Docker)" describes the pattern for running the whole agent in Docker. The default Compose file uses network_mode: host, which gives the agent unrestricted outbound access. The override below puts the agent on an internal network with no default route and sends permitted traffic through an allowlisting proxy. Docker's Compose reference describes internal: true as creating "an externally isolated network."
# docker-compose.override.yml, adapted from the Hermes network isolation guide
networks:
internal:
driver: bridge
internal: true # no default route, no internet
egress:
driver: bridge
services:
gateway:
network_mode: "" # clear the host-mode default
networks: [internal, egress]
environment:
- HTTP_PROXY=http://egress-proxy:3128
- HTTPS_PROXY=http://egress-proxy:3128
- NO_PROXY=hermes,hermes-dashboard,localhost
ports:
- "127.0.0.1:9119:9119" # dashboard proxy on localhost only
dashboard:
network_mode: ""
networks: [internal]
egress-proxy:
image: ubuntu/squid:6.10-24.04_edge # pin by digest in production
networks: [egress]
volumes:
- ./config/squid-allowlist.conf:/etc/squid/conf.d/allowlist.conf:ro
restart: unless-stopped
# config/squid-allowlist.conf: allow HTTPS CONNECT only to hosts you need
acl allowed_hosts dstdomain inference.nousresearch.com
acl allowed_hosts dstdomain api.telegram.org
http_access allow CONNECT allowed_hosts
http_access deny all
Add your model provider's API host and each messaging platform you enable, and nothing else. Then prove the policy works, using the checks from the same guide:
# Must FAIL: arbitrary egress
docker compose exec gateway curl -sf --max-time 5 https://example.com \
&& echo "FAIL: egress not blocked" || echo "OK: egress blocked"
# Must SUCCEED: internal service
docker compose exec gateway curl -sf --max-time 5 http://hermes-dashboard:9119/health \
&& echo "OK: internal reachable" || echo "FAIL"
The guide lists its own limits. Containers on the internal network can still resolve external DNS names unless you run a resolver that refuses outside queries. The gateway needs egress for every messaging platform you add. And segmentation does not replace a sandboxed terminal backend. Our post on starting with default-deny egress for an agent sandbox covers DNS and proxy choices in more depth.
6. How do you set approvals and lock down who can talk to it?
Approval modes
approvals.mode takes three values. smart, the default since v0.19.0, asks an auxiliary model to judge risk: low-risk commands are approved for that one command, clearly dangerous ones are denied, and uncertain ones come to you. manual always prompts for flagged commands. off disables approval checks and is the same as --yolo.
| Setting | Default | Hardened value | Why |
|---|---|---|---|
approvals.mode | smart | manual | You see every flagged command; no model approves on your behalf |
approvals.timeout | 300 | 300 | Unanswered prompts are denied, so walking away never approves |
approvals.cron_mode | deny | deny | Cron jobs have no human to answer |
approvals.single_query_mode | deny | deny | One-shot -q runs have no human either |
approvals.unattended_mode | deny | deny | Webhook and API sessions block flagged commands instantly |
approvals.deny | empty | Your never-run list | Blocks matches even under --yolo and mode: off, in every backend |
command_allowlist | empty | Empty, audited | "Always" approvals land here and are silently approved forever |
Under all of this sits a hardline blocklist that no setting overrides: root filesystem wipes, fork bombs, formatting a mounted root device, zeroing a disk, and piping untrusted URLs to a shell at the top level. It also fails closed on commands whose quoting cannot be parsed.
approvals:
mode: manual
timeout: 300
cron_mode: deny
single_query_mode: deny
unattended_mode: deny
deny:
- 'git push --force*'
- '*curl*|*sh*'
- 'dd if=* of=/dev/*'
- 'sudo *'
command_allowlist: []
Always quote deny patterns: a bare leading * is a YAML alias and fails to parse. Matching is case-insensitive and runs over normalised command variants, so simple quoting tricks do not slip past, but the docs call it "a shell-command policy, not a complete shell interpreter or an OS capability sandbox": it does not resolve variables, aliases, renamed binaries or interpreter programs. Treat it as a stop signal, not containment.
Audit command_allowlist on a schedule. Every "always" click saves a pattern that is approved in all future sessions, including unattended ones when the entry is a rule key. hermes approvals suggest mines your approval history, which helps find what has crept in.
--yolo, /yolo and HERMES_YOLO_MODE=1 bypass every prompt except the hardline floor and your approvals.deny rules, and /yolo is saved with the session until you toggle it off or start a new conversation.
Who can talk to the gateway
The gateway authorises in a fixed order: per-platform allow-all, DM pairing approvals, per-platform allowlists, the global allowlist, global allow-all, then deny. With no allowlist and no allow-all flag, everyone is denied and the gateway logs a warning. Keep it explicit:
# ~/.hermes/.env
TELEGRAM_ALLOWED_USERS=123456789
GATEWAY_ALLOWED_USERS=123456789
# Never set GATEWAY_ALLOW_ALL_USERS=true or a per-platform *_ALLOW_ALL_USERS on a machine you care about
Also check config.yaml for gateway.allow_all_users: true, which the docs say is bridged to the same environment variable at startup.
DM pairing is the alternative to hardcoding IDs: an unknown user receives an eight-character code that expires after an hour, and you approve it with hermes pairing approve <platform> <code>. If you do not want strangers to learn the bot exists, set unauthorized_dm_behavior: ignore. Review approved users regularly:
hermes pairing list
hermes pairing revoke telegram 123456789
hermes pairing clear-pending
If Hermes runs in the official Docker image, run pairing commands as the hermes user (docker exec -u hermes ...); the docs note that approvals written by root are unreadable to the gateway and silently ignored.
The security policy adds the network side: do not expose the gateway or API server to the public internet without a VPN or firewall in front, and configure a caller allowlist for every network-exposed adapter.
7. How do you review the skills and memories Hermes writes?
This is the part of hardening specific to a self-improving agent. Hermes saves skills after multi-step tasks, after finding a path past errors and after you correct it, and a background review after a turn can write skill and memory changes too. A wrong lesson, or a procedure shaped by text the agent read on a hostile page, persists into future sessions. Our posts on memory poisoning and memory hardening and on the limits of static scanners for agent skills explain the attack class; here is the Hermes configuration that puts a human between the agent and its own long-term state.
Turn on the write gates
skills:
write_approval: true # default false: every skill_manage write is staged
guard_agent_created: true # default false: scanner prompts on flagged skill writes
memory:
write_approval: true # default false: memory saves wait for your yes or no
With skills.write_approval: true, every skill_manage action (create, patch, delete, write_file, remove_file) is staged under ~/.hermes/pending/skills/ instead of applied, whether it came from a foreground turn or the background review. Staged writes survive restarts. Review them like a pull request:
/skills pending # list staged writes with a one-line gist each
/skills diff <id> # full unified diff; read it on the CLI, not in a chat bubble
/skills approve <id>
/skills reject <id>
With memory.write_approval: true, foreground saves in the interactive CLI prompt inline, and everything else (messaging platforms, scripts, the background review) is staged for /memory pending, /memory approve <id> and /memory reject <id>. The memory files are small, which makes review practical: MEMORY.md is capped at 2,200 characters and USER.md at 1,375 characters, confirmed in the v0.22.5 defaults.
skills.guard_agent_created is a separate content scanner for credential harvesting, injection and exfiltration patterns. The docs say it was turned off by default because legitimate workflows that mention ~/.ssh/ or an API key variable tripped it too often. Turn it on anyway; a false positive costs a click.
What to look for in a staged skill diff
Read a skill diff the way you would read a shell script someone sent you, because that is close to what it is. Check whether the procedure:
- runs commands that fetch and execute remote content, or installs packages that the task did not need;
- touches credential paths,
.envfiles, SSH configuration or the Hermes home directory; - tells the agent to skip approvals, toggle YOLO, disable a check or hide its actions;
- adds or changes
required_environment_variablesorrequired_credential_filesin the frontmatter, which widens what the sandbox receives; - adds files under
scripts/, which the security policy notes can contain executable code; - names hosts you do not recognise, or quotes instructions that came from a web page or email rather than from you.
Keep agent-written skills in git
skills.create_dir redirects new agent-created skills to a directory you choose, such as a git repository. The docs are precise about its scope: new skills go there, but existing skills are still modified wherever they live, and the hub and the curator keep working on the profile-local ~/.hermes/skills/. To get a full audit trail, version both.
skills:
create_dir: ~/hermes-skills
# Baseline both skill locations in git
mkdir -p ~/hermes-skills
for d in ~/hermes-skills ~/.hermes/skills; do
git -C "$d" init -q 2>/dev/null || true
git -C "$d" add -A
git -C "$d" commit -qm "baseline $(date -u +%Y-%m-%dT%H:%MZ)" || true
done
# Later: see exactly what the agent changed
git -C ~/.hermes/skills status --short
git -C ~/.hermes/skills diff
git -C ~/hermes-skills log -p --since=yesterday
Commit after each review session so every approved change has its own commit. If you share skills across a team, push the repository and require pull request review before anything lands on the branch that other installs pull from. Our post on why agent skills need the same governance as packages covers that workflow.
Undo with backups first
Reverting skill state, rolling back a checkpoint or clearing memory changes what the agent knows and can lose work. Take a backup before every one of these operations.
Warning: the next block discards uncommitted skill changes. Back up first.
# 1. Back up the whole Hermes home before reverting anything
hermes backup
tar czf ~/hermes-home-$(date -u +%Y%m%dT%H%MZ).tgz -C ~ .hermes
# 2. Inspect what would be lost
git -C ~/.hermes/skills status --short
git -C ~/.hermes/skills diff
# 3. Only then revert the working tree to the last reviewed commit
git -C ~/.hermes/skills restore --staged --worktree .
Hermes's own checkpoints are a second undo layer for project files. When checkpoints.enabled: true (default false), Hermes snapshots the working directory into a shadow git store under ~/.hermes/checkpoints/store/ before file edits and destructive commands, without touching your project's .git.
Warning: /rollback <N> restores files and also undoes the last chat turn. Back up and preview first.
# In a shell first: hermes backup
/rollback # list checkpoints
/rollback diff 3 # preview what checkpoint 3 would change
/rollback 3 # restore only after reading the diff
Destructive session commands such as /clear, /new, /reset and /undo ask for confirmation by default because approvals.destructive_slash_confirm is true. Do not click "Always Approve" on that prompt on a shared install.
8. How do you handle project skills, Skills Hub installs, plugins, gateway hooks and lazy installs?
Everything in this section runs inside or alongside the agent process, which the security policy says a terminal sandbox does not confine. The policy's rule for all of it is the same: review before install, and read the code, not just the description.
Project skills: trust only repositories you control
When you start Hermes inside a git checkout, it looks for skills in .hermes/skills/ and .agents/skills/ at the project root. It does not load them until you run hermes skills trust, and project skills take the highest precedence, so a repo skill called deploy overrides your own. Every project skill is scanned before it enters the index and quarantined if the verdict is dangerous, with scans cached by content hash and re-run when content changes.
A git pull can still change a trusted repo's skills, and the scanner is a heuristic. Trust your own repositories, not ones you are evaluating; revoke with hermes skills untrust, or set skills.project_discovery: false to switch the feature off. Cron jobs inherit your trust decisions for their working directory.
Skills Hub and URL installs
hermes skills install copies SKILL.md and the files it references into a quarantine, scans the bundle and records the source URL, exact content hash, scanner version, findings and timestamp in skills/.hub/lock.json. Use that as an inventory and as a review aid:
hermes skills inspect <source/path> # preview before installing
hermes skills install <source/path> # installs with the security scan
hermes skills audit # re-scan everything installed from the hub
hermes skills check # look for upstream changes before updating
cat ~/.hermes/skills/.hub/lock.json # what came from where, at which hash
Treat hermes skills update like a dependency upgrade: check what changed upstream, read the diff, then update, and avoid --force installs.
Plugins
General plugins are disabled until named in plugins.enabled, and hermes plugins install asks before enabling, defaulting to no. Pin installs to a commit with --ref, and the docs say hermes plugins update will not move a pinned plugin. Since v0.22.0 you can opt into plugins.isolation: host, which runs third-party plugins in a separate per-profile process that only holds that profile's secrets. The default is in_process, where a plugin runs with full agent privileges.
hermes plugins install owner/repo --ref <full-commit-sha> --no-enable
# read the code, its dependencies and any services it starts, then:
hermes plugins enable <name>
Gateway hooks are trusted by placement
This is the one extension point with no opt-in. Any directory under ~/.hermes/hooks/ with a valid HOOK.yaml and handler.py is imported by the gateway at startup with the gateway's privileges: no prompt, no plugins.enabled check, and safe mode does not skip it. The docs say this is deliberate, because anyone who can write to the profile home can already run code as you, and the directory is not on the write-protected path list. Add it to every audit.
Shell hooks prompt on first use and are remembered in ~/.hermes/shell-hooks-allowlist.json; keep hooks_auto_accept: false. The allowlist keys on the command string, not the script's hash, so hermes hooks doctor is how you spot edited scripts.
ls -la ~/.hermes/hooks/
hermes hooks doctor
Lazy installs of optional dependencies
When a feature needs an optional Python extra, Hermes's package manager can install it on first use, within the committed lock and only for declared extra names. That keeps installs reproducible, but it still changes the environment the agent runs in while it runs. On a hardened install, turn it off and add extras deliberately:
hermes config set security.allow_lazy_installs false
MCP servers
Each MCP server gets only safe system variables plus its own env block. Limit what each server contributes, and switch off sampling, which lets a server ask Hermes's model to generate text and is on by default:
mcp_servers:
github:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github@<pinned-version>"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PAT_READONLY}"
tools:
include: [list_issues, get_issue, search_code]
sampling:
enabled: false
Pin the server package version instead of fetching the latest on every launch, give it a token with the narrowest scope that works, and keep approvals.mcp_reload_confirm: true so a tool set change is never silent.
9. What should a hardened config.yaml look like, and how do you check and update it?
A hardened configuration, end to end
The file below combines everything above. Every key appears in the Hermes docs or the v0.22.5 defaults; comments give the default where it differs. Adapt hosts, paths and limits to your setup.
# ~/.hermes/config.yaml: hardened profile, checked against v0.22.5 on 23 Oct 2026
approvals:
mode: manual # default: smart
timeout: 300
cron_mode: deny
single_query_mode: deny
unattended_mode: deny
mcp_reload_confirm: true
destructive_slash_confirm: true
deny:
- 'git push --force*'
- '*curl*|*sh*'
- 'dd if=* of=/dev/*'
- 'sudo *'
command_allowlist: []
terminal:
backend: docker # default: local
docker_image: "nousresearch/hermes-sandbox@sha256:<pinned-digest>"
docker_forward_env: []
env_passthrough: []
container_cpu: 1
container_memory: 4096 # default: 5120
container_persistent: false # default: true
proxy:
enabled: true # default: false
enforce_on_docker: true
credential_source: env
extra_allowed_hosts: []
security:
redact_secrets: true
allow_private_urls: false
allow_lazy_installs: false # default: true
website_blocklist:
enabled: true # default: false
domains:
- "*.internal.example.com"
skills:
write_approval: true # default: false
guard_agent_created: true # default: false
create_dir: ~/hermes-skills
project_discovery: true
trusted_project_dirs: []
memory:
write_approval: true # default: false
checkpoints:
enabled: true # default: false
plugins:
isolation: host # default: in_process
enabled: []
hooks_auto_accept: false
auth:
adopt_external_logins: false # default: true
unauthorized_dm_behavior: ignore # default: pair on chat DM platforms
updates:
pre_update_backup: full # default: quick
And the environment side:
# ~/.hermes/.env (chmod 600)
GATEWAY_ALLOWED_USERS=123456789
# Optional write sandbox for write_file and patch; include the Hermes home or the
# agent cannot update its own state:
# HERMES_WRITE_SAFE_ROOT=/srv/agent-work:/home/agent/.hermes
HERMES_WRITE_SAFE_ROOT restricts the file tools to listed prefixes, and the official Docker image already sets it to /opt/data. The docs warn not to add it casually, because a project-only value stops the agent writing cron jobs and skills in its own home.
Step by step: from a fresh machine to a hardened gateway
- Create a dedicated, non-root service user. The security checklist says never run the gateway as root.
- Install as that user from a read and pinned installer, with
--skip-browserand--skip-computer-useunless you need them (question 1). - Run
hermes doctorandhermes update --check. Do not add keys until both are clean. - Lock down
~/.hermes(chmod 700) and.env(chmod 600). Add only the provider key and the one messaging token you need. - Copy the hardened
config.yamlabove. Pin the sandbox image by digest. - Run
hermes egress install,hermes egress setupandhermes egress start, and confirmhermes egress statusbefore the first sandboxed command. - If the agent will read the open web, inbound email or group chats, run the whole agent in the official image on an internal Docker network behind an allowlisting proxy, and run the two validation
curlchecks (question 5). - Set
GATEWAY_ALLOWED_USERSor use DM pairing, and setunauthorized_dm_behavior. - Initialise git in
~/hermes-skillsand~/.hermes/skills, and commit a baseline. - Run a test session that asks the agent to save a skill and a memory. Confirm both appear under
/skills pendingand/memory pendinginstead of landing directly. - Ask the agent to run a harmless command that matches one of your deny rules and confirm it is blocked, then ask for a flagged command and confirm you get a manual prompt.
- Record the install hash, release commit, image digests and config file hash in your change log.
Checking and keeping it current
hermes doctor # config, dependencies, storage, advisories, install provenance
hermes config check # find missing or renamed keys after an update
hermes update --check # what would change, without applying it
hermes update --plan # read-only view of services and restarts on this machine
hermes update --backup # full pre-update backup of HERMES_HOME, then update
git -C ~/.hermes/hermes-agent status --short # source installs: inspect a dirty tree
hermes --version
New source installs follow the stable channel, which the updating docs define as the latest published vX.Y.Z release, never a draft, prerelease or canary, checked out at its exact commit. Leave it there. hermes update --set-channel main follows every commit and is for contributors.
The docs also warn that an older release cannot run on a state.db that a newer gateway runtime has written, and hermes update will refuse such a rollback. If you must go back, stop the gateway, check out the older release and restore the pre-update snapshot or a full backup taken with hermes update --backup. That is the main reason to set updates.pre_update_backup: full on a production gateway.
Finally, re-read the security page and the release notes when you update. Defaults do change: smart approvals became the default in v0.19.0, the sandbox image changed in v0.22.0, and v0.22.5's notes defer full documentation of about 81 merged pull requests to v0.23.0.
Where Safeguard fits, honestly
Hermes Agent is not a Safeguard product, integration or partner, and Safeguard does not scan, monitor or govern Hermes Agent as such. The overlap is narrower and more ordinary. A hardened Hermes install is still a large open source software supply chain: the agent's own Python and Node dependency tree, the sandbox image, plugins and their dependencies, MCP server packages, and the scripts inside skills, including the ones the agent writes. When you ask the agent to build something, the packages it installs and the code it writes end up in your repositories.
That part is what Safeguard is built for, on any codebase. You can generate an SBOM (SPDX or CycloneDX) for the repository that holds your agent-written skills and scripts, for the directory where a plugin lives, or for the sandbox image; match those components against vulnerability data; and use policies and gates in CI so a vulnerable dependency added by an agent fails the same check as one added by a person. Attestation and signing with SLSA, Sigstore and in-toto provenance apply to the images and artifacts you build from that work. What Safeguard does not do here is review skill text for injected instructions or tell you whether a skill is malicious; that review is yours, using the Hermes gates above.
Common mistakes
- Running a gateway on the
localbackend. Anyone who can message the bot, and anything it reads, can steer commands that run as you. Usedockerorssh, and wrap the whole agent for untrusted inputs. - Treating the approval gate as a sandbox. Hermes's policy calls it a heuristic for cooperative mistakes. Containment comes from the OS, the container and the network.
- Clicking "always" on approval prompts. Each click adds to
command_allowlist, which is approved silently in every future session, including some unattended ones. - Adding provider keys to
docker_forward_env. The docs warn that code in the container can read and exfiltrate them. Use the egress credential proxy instead. - Leaving
skills.write_approvaloff on a gateway. The background review can write skills after every turn. Without the gate, nobody reads them before the next session follows them. - Git-tracking only
skills.create_dir. Existing skills are patched where they live, and the hub and curator work in~/.hermes/skills/. Track both. - Running
hermes skills truston a repo you are evaluating. Project skills take the highest precedence and change with every pull. - Forgetting
~/.hermes/hooks/. Gateway hooks load by placement with no prompt. - Using
network_mode: hostfor the agent container. That is the stock Compose default and gives unrestricted egress. - Pinning by mutable tag.
stable,latestanddesktopmove. Pin images by digest and source installs by release commit. - Rolling back without a backup.
/rollbackalso undoes the last chat turn, and an older release refuses to run on a newerstate.db.
FAQ
Is Hermes Agent safe to run?
It can be, if you match isolation to what it reads. The project's policy says the operating system is the only real boundary against a manipulated model. For personal use on trusted inputs, the defaults plus manual approvals are reasonable. For a gateway, untrusted web or email content, or shared machines, use a container backend, wrap the whole agent in a network-restricted container, and turn on the skill and memory write gates.
What is the safest terminal backend for Hermes Agent?
For most people it is docker, because Hermes runs each sandbox with all capabilities dropped (minus a small add-back), no-new-privileges, a process limit and size-limited temporary filesystems. ssh is a good choice when you want execution on a separate host. local runs on your machine with no isolation and is only appropriate for trusted use.
How do I stop Hermes Agent from seeing my API keys?
Keep keys in ~/.hermes/.env with mode 600 or in a password manager integration, leave docker_forward_env and env_passthrough empty, and enable the egress credential proxy with hermes egress setup so the Docker sandbox only holds stand-in tokens. Set auth.adopt_external_logins: false if you do not want Hermes reading other CLIs' login files.
How do I review the skills Hermes Agent writes?
Set skills.write_approval: true. Every create, patch, delete or file write is staged under ~/.hermes/pending/skills/, and you review it with /skills pending, /skills diff <id>, /skills approve <id> and /skills reject <id>. Keep the skill directories in git so approved changes have a history.
Does Hermes Agent train or change its own model?
No. Its "self-improving" behaviour comes from memory files, saved skills and session search, not from updating model weights. That is why the things to govern are files on disk: MEMORY.md, USER.md, the skills directories and the session database.
Can I stop Hermes Agent from writing to memory at all?
Yes. memory.write_approval: true makes every save wait for approval. To turn built-in memory off entirely, set both memory_enabled: false and user_profile_enabled: false, which also hides the memory tool.
How do I restrict Hermes Agent's internet access?
Use the SSRF guard (always on) and the website blocklist for Hermes's own tools, then put the agent container on an internal Docker network with an allowlisting proxy so shell commands cannot reach arbitrary hosts. Test it with a curl that must fail. Remember that DNS can still resolve unless you also control the resolver.
Is --yolo ever acceptable?
Only in a disposable environment you are prepared to lose, such as a throwaway container running tested automation. YOLO still respects the hardline blocklist and your approvals.deny rules, but it skips every other prompt, and it persists with the session.
How do I update Hermes Agent safely?
Stay on the stable channel, run hermes update --check and hermes update --plan, then hermes update --backup. Afterwards run hermes doctor, hermes config check and hermes --version, and read the release notes for default changes. Pin Docker images by digest and move the pin deliberately.
What is the difference between Hermes Agent and the Hermes models?
Hermes Agent is the open source agent harness covered here; it is provider-agnostic and can use many models. The Hermes models are Nous Research's separate family of open-weight fine-tuned language models. Hardening the agent is about its tools, files, network and credentials, whichever model drives it.
Fix it without waiting for upstream
A hardened agent still pulls packages, plugins, MCP servers and sandbox images, and the scripts it writes into skills and repositories become part of your codebase. Every one of those is an open source component that can receive a CVE, so the same patching discipline you apply to application dependencies applies here.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo is a real Safeguard CLI session. It asks the assistant to fix a lodash CVE in a repository; the assistant reads the finding and the advisory, asks before each command, edits package.json, runs npm install and npm test with approval, and pushes nothing. That ask-before-every-command flow is the same discipline this post recommends for Hermes, applied to fixing a dependency in a repository where an agent's work has landed.
Click through it at your own pace, or open it full screen.
The second demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. In practice you add Safeguard from Claude's connector directory rather than writing a custom MCP config. The point for this topic is the same as tools.include in Hermes: an assistant should get the narrowest set of tools that does the job.
Click through it at your own pace, or open it full screen.
The third demo sets up the Safeguard runner on your own machine, approves it with a device code and runs a scan from the terminal. If you keep agent-written skills and scripts in a local repository, this is how you would scan that repository where it lives.
Click through it at your own pace, or open it full screen.
To try it yourself, download Safeguard and read the CLI docs.
Quick check
Your Hermes gateway reads inbound email and runs on the local backend with approvals set to manual. Is that within Hermes's supported security posture?
No. Hermes's security policy says running the default local backend with untrusted input surfaces is outside the supported posture, because approval prompts are heuristics. Move execution to a container backend and wrap the whole agent in a network-restricted container.
You set skills.create_dir to a git repository. Does that give you a complete history of every skill change the agent makes?
No. Only new agent-created skills go to create_dir. Existing skills are patched where they live, and the hub and curator keep working in ~/.hermes/skills/, so track that directory in git too and turn on skills.write_approval.
Sources
- Hermes Agent repository (GitHub API metadata, read 23 Oct 2026)
- Hermes Agent releases (GitHub API, all 44 releases)
- Hermes Agent v0.22.5 release notes
- Hermes Agent v0.22.0 "Threshold" release notes
- Hermes Agent v0.19.0 "Quicksilver" release notes
- Hermes Agent SECURITY.md (trust model and deployment hardening)
- Hermes Agent config defaults at the v0.22.5 tag
- Hermes Agent install.sh
- Hermes docs: Installation
- Hermes docs: Updating and uninstalling
- Hermes docs: Termux
- Hermes docs: Security
- Hermes docs: Running Hermes on a personal or work machine
- Hermes docs: Docker
- Hermes docs: Network egress isolation (Docker)
- Hermes docs: Egress proxy
- Hermes docs: Skills
- Hermes docs: Memory
- Hermes docs: MCP
- Hermes docs: Configuration
- Hermes docs: Checkpoints and rollback
- Hermes docs: Plugins
- Hermes docs: Hooks
- Hermes docs: Import from other agents
- Nous Research releases page
- Docker Hub: nousresearch/hermes-agent tags
- CVE.org: CVE-2026-71963
- CVE.org: CVE-2026-85105
- Docker docs: docker container run reference
- Docker docs: Engine security
- Docker docs: Rootless mode
- Docker docs: Compose networks reference
- NIST SP 800-190: Application Container Security Guide
- OWASP Top 10 for LLM Applications 2025: LLM06 Excessive Agency
- OWASP: Agentic AI Threats and Mitigations
Last reviewed: 23 October 2026. Hermes Agent ships several releases a week; check the linked docs and release notes for current defaults before you deploy.