Safeguard
Supply Chain Security•

How to Install and Harden Hermes Agent: Sandbox, Secrets, Egress

Install Hermes Agent from a pinned stable release, move commands into Docker, keep keys out, default-deny egress and stage every skill and memory write.

Safeguard Security Team
50 min read

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. Use docker or ssh for 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_env is 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, set approvals.mode: manual and add your own approvals.deny rules, which hold even under --yolo.
  • Install from the stable channel, pin a release commit or image digest, and run hermes update --check and hermes doctor before 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.

DateVersionWhat changed for security and operations
22 Jul 2025(repository created)Pre-public foundation work begins (GitHub API created_at)
25 Feb 2026Public launchListed on nousresearch.com/releases as an agent that "lives on your server"
12 Mar 2026v0.2.0First tagged release after the pre-public v0.1.0 foundation
7 May 2026v0.13.0 "Tenacity"Named release in the CalVer tag series
28 May 2026v0.15.0 "Velocity"Named release; v0.15.1 patch followed on 29 May
5 Jun 2026v0.16.0 "Surface"Desktop app and web dashboard (published 6 Jun UTC)
1 Jul 2026v0.18.0 "Judgment"Self-verification and /learn, which turns sources into skills
20 Jul 2026v0.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 2026v0.21.6First SemVer tag through the new stable release gate; dashboard sign-in hardening and automatic git operations skip repository filter programs
13 Oct 2026v0.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 2026v0.22.5Latest 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:

  1. 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.
  2. 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

ThreatWhat it looks like in HermesPrimary controlBackup controlDefault on 23 Oct 2026
Destructive or unwanted shell commandModel runs a command that deletes, overwrites or reconfiguresContainer or SSH terminal backendapprovals.mode: manual, approvals.deny, checkpointsBackend local, approvals smart, checkpoints off
Credential theft from the sandboxInjected instruction reads environment variables or token filesEmpty docker_forward_env, egress credential proxyEnv filtering for subprocesses, output redactionForwarding empty, proxy off, redaction on
Data exfiltration over the networkCommand posts files or secrets to an outside hostWhole-process container on an internal network with an allowlisting proxySSRF guard, website blocklist, content-level curl checksContainer networking is host mode in the default Compose file; SSRF guard on
Strangers driving your agentSomeone messages the gateway botPlatform allowlists or DM pairingunauthorized_dm_behavior: ignoreDeny all unless allowlisted; pairing replies on chat DMs
Poisoned skill or memory that persistsA bad lesson or injected procedure is saved and reused in later sessionsskills.write_approval, memory.write_approval, git-tracked skillsskills.guard_agent_created scannerBoth gates off; guard off
Untrusted repository contentProject skills, context files or git config in a cloned repohermes skills trust only for repos you control; current releaseScan-time quarantine, context file injection scannerProject skills not loaded until trusted
Third-party code in the agent processPlugins, hooks, Skills Hub installs, lazy dependency installsReview before install, pin refs, plugins.isolation: hostsecurity.allow_lazy_installs: false, hermes skills auditPlugins disabled until enabled; lazy installs on
MCP server misuseA server receives secrets or asks the agent's model for textExplicit env per server, tools.include, sampling offCredential redaction in MCP errorsEnv filtered; sampling on
Stale, vulnerable installKnown bugs stay in placeStable channel, hermes update --check, pinned digestBuilt-in advisory check in hermes doctorStable 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.

BackendWhere commands runDangerous-command checkGood fitPoor fit
local (default)Your host, as your userYesA trusted user, trusted inputs, a throwaway machineAny gateway, any untrusted web or email content, any machine with production credentials
sshA separate machine you controlYesKeeping the gateway and the execution host apartCases where the remote host also holds sensitive data
dockerA hardened container on your hostSkipped; the container is the boundaryA personal or work machine, a production gatewayWorkloads that need host devices or host credentials
Singularity pluginA container on HPC systemsSkippedShared research clustersDesktops
Hosted cloud sandbox backendsA provider's sandbox or microVMSkippedScalable or disposable executionData 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 of DAC_OVERRIDE, CHOWN and FOWNER so package managers can work. SETUID and SETGID are 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 stops su, sudo and setuid binaries from raising privileges.
  • --pids-limit 256 to cap process count.
  • A size-limited /tmp (512 MB, nosuid) and a noexec /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 processDefault filterHow variables get through
execute_codeBlocks names containing KEY, TOKEN, SECRET, PASSWORD, CREDENTIAL, PASSWD or AUTH, and only allows safe-prefix variablesSkill-declared variables and terminal.env_passthrough
terminal with localBlocks Hermes infrastructure variables (provider keys, gateway tokens, tool keys)Same passthrough lists
terminal with dockerNo host variables at allPassthrough lists plus docker_forward_env
terminal with sshNo host variablesPassthrough via SendEnv, which needs a matching AcceptEnv on the server
MCP stdio serversOnly 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.

SettingDefaultHardened valueWhy
approvals.modesmartmanualYou see every flagged command; no model approves on your behalf
approvals.timeout300300Unanswered prompts are denied, so walking away never approves
approvals.cron_modedenydenyCron jobs have no human to answer
approvals.single_query_modedenydenyOne-shot -q runs have no human either
approvals.unattended_modedenydenyWebhook and API sessions block flagged commands instantly
approvals.denyemptyYour never-run listBlocks matches even under --yolo and mode: off, in every backend
command_allowlistemptyEmpty, 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, .env files, 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_variables or required_credential_files in 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

  1. Create a dedicated, non-root service user. The security checklist says never run the gateway as root.
  2. Install as that user from a read and pinned installer, with --skip-browser and --skip-computer-use unless you need them (question 1).
  3. Run hermes doctor and hermes update --check. Do not add keys until both are clean.
  4. Lock down ~/.hermes (chmod 700) and .env (chmod 600). Add only the provider key and the one messaging token you need.
  5. Copy the hardened config.yaml above. Pin the sandbox image by digest.
  6. Run hermes egress install, hermes egress setup and hermes egress start, and confirm hermes egress status before the first sandboxed command.
  7. 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 curl checks (question 5).
  8. Set GATEWAY_ALLOWED_USERS or use DM pairing, and set unauthorized_dm_behavior.
  9. Initialise git in ~/hermes-skills and ~/.hermes/skills, and commit a baseline.
  10. Run a test session that asks the agent to save a skill and a memory. Confirm both appear under /skills pending and /memory pending instead of landing directly.
  11. 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.
  12. 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 local backend. Anyone who can message the bot, and anything it reads, can steer commands that run as you. Use docker or ssh, 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_approval off 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 trust on 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: host for the agent container. That is the stock Compose default and gives unrestricted egress.
  • Pinning by mutable tag. stable, latest and desktop move. Pin images by digest and source installs by release commit.
  • Rolling back without a backup. /rollback also undoes the last chat turn, and an older release refuses to run on a newer state.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 situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull 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

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.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.