Skip to content

Security

Threat model, sandboxing strategy, and hardening guidance for Hermes Agent.

Security Track Record

As of April 2026, Hermes Agent has zero agent-specific CVEs. This contrasts sharply with OpenClaw, which accumulated 9 CVEs within 4 days of its March 2026 release. The difference is partly attributable to Hermes's smaller attack surface (fewer platform integrations, no marketplace of third-party skills with arbitrary code execution) and its container-first isolation model for code execution.

Threat Model

flowchart TB
    subgraph External["External Attack Surface"]
        GW["Gateway Channels<br>(Telegram, Discord, Slack, ...)"]
        API["API Server<br>(REST endpoint)"]
        WEB["Web Dashboard"]
    end

    subgraph Internal["Internal Attack Surface"]
        PLUGIN["Plugin System<br>(arbitrary Python)"]
        SKILL["Skills<br>(markdown + instructions)"]
        TERM["Terminal Backends<br>(code execution)"]
        KEYS["API Keys<br>(~/.hermes/.env)"]
        DB["Session Database<br>(SQLite on disk)"]
        EVOL["Self-Evolution<br>(prompt mutation)"]
    end

    GW -->|Auth: ALLOWED_USERS| AGENT[Agent Core]
    API -->|Auth: API_SERVER_KEY| AGENT
    WEB -->|No built-in auth| AGENT
    AGENT --> PLUGIN
    AGENT --> SKILL
    AGENT --> TERM
    AGENT --> KEYS
    AGENT --> DB
    AGENT --> EVOL

Attack Surfaces

Surface Risk Mitigation
Gateway channels Unauthorized messages from non-allowed users *_ALLOWED_USERS env var per platform
API server Remote code execution via REST API_SERVER_KEY required for non-loopback binding
Web dashboard Credential exposure (reads/writes .env) Binds to 127.0.0.1 by default; no built-in auth
Plugin system Arbitrary Python execution User must explicitly place files in ~/.hermes/plugins/
Terminal backends Shell command injection Dangerous command approval + container isolation
API keys Credential theft from disk File permissions (chmod 600), env-only storage
Session database History exposure Local SQLite file, inherits OS file permissions
Self-evolution Skill degradation, malicious mutations Pareto selection, test-case validation, human review

Sandboxing

Docker Backend Isolation

When using the Docker terminal backend, Hermes applies strict security hardening to every container:

_SECURITY_ARGS = [
    "--cap-drop", "ALL",                          # Drop ALL Linux capabilities
    "--cap-add", "DAC_OVERRIDE",                  # Root can write to bind-mounted dirs
    "--cap-add", "CHOWN",                         # Package managers need file ownership
    "--cap-add", "FOWNER",                        # Package managers need file ownership
    "--security-opt", "no-new-privileges",         # Block privilege escalation
    "--pids-limit", "256",                         # Limit process count
    "--tmpfs", "/tmp:rw,nosuid,size=512m",         # Size-limited /tmp
    "--tmpfs", "/var/tmp:rw,noexec,nosuid,size=256m",  # No-exec /var/tmp
    "--tmpfs", "/run:rw,noexec,nosuid,size=64m",   # No-exec /run
]

Key protections:

  • All Linux capabilities dropped except three required for package management
  • Privilege escalation explicitly blocked via no-new-privileges
  • Process count capped at 256 to prevent fork bombs
  • Temporary directories are size-limited and mounted with noexec/nosuid

Singularity / Modal / Daytona Isolation

Container-based backends (Singularity, Modal, Daytona) provide namespace isolation from the host. Modal and Daytona run in cloud-managed sandboxes with additional provider-level isolation. For all container backends, dangerous command checks are skipped because the container itself is the security boundary.

Container image trust

The default image (nikolaik/python-nodejs:python3.11-nodejs20) is a community-maintained image. For production deployments, consider building and hosting your own images from a trusted base.

Dangerous Command Approval (Local Backend)

The local backend checks every command against a curated list of dangerous patterns before execution:

  • Recursive deletes (rm -rf)
  • SQL drops (DROP TABLE, DROP DATABASE)
  • Piping curl to shell (curl ... | bash)
  • Permission changes on system directories
  • Other destructive patterns

When a dangerous command is detected, the agent presents an interactive approval prompt with options: [o]nce, [s]ession, [a]lways, or [d]eny.

API Key Management

API keys are stored in ~/.hermes/.env and managed via the CLI:

hermes config set OPENROUTER_API_KEY sk-or-...   # Auto-routed to .env
hermes config set ANTHROPIC_API_KEY sk-ant-...

File permissions

Restrict .env to owner-only access:

chmod 600 ~/.hermes/.env

Best practices:

  • Never commit .env files to version control
  • Use per-profile .env files (~/.hermes/profiles/<name>/.env) to isolate credentials between use cases
  • In Docker, pass keys via -e flags instead of mounting .env to avoid on-disk storage
  • Use env_passthrough in config.yaml to forward only required keys to sandboxed backends

Channel Authentication

Each platform adapter enforces an allowlist of authorized user IDs:

Platform Env Variable Format
Telegram TELEGRAM_ALLOWED_USERS Comma-separated numeric user IDs
Discord DISCORD_ALLOWED_USERS Comma-separated Discord user IDs
Slack SLACK_ALLOWED_USERS Comma-separated Slack Member IDs

Messages from users not in the allowlist are silently dropped. There is no open-registration mode.

Memory and Session Data Protection

Session data is stored in local SQLite files under ~/.hermes/. Protection relies on:

  • OS file permissions — SQLite files inherit the permissions of the Hermes data directory
  • Per-platform session isolation — sessions from different platforms are stored separately, preventing cross-channel data leakage
  • Atomic writes — contention handling prevents corruption during concurrent access

No encryption at rest

SQLite session data is not encrypted at rest. If the host is compromised, all conversation history is accessible. For sensitive environments, run Hermes in an encrypted filesystem or use a container backend with ephemeral storage.

Self-Evolution Safety

The DSPy + GEPA self-evolution system introduces a unique risk: autonomous modification of skills and prompts could degrade agent quality or introduce harmful behaviors.

Safeguards:

  • Test-case validation — every mutated variant is evaluated against test cases before acceptance
  • Pareto selection — variants must be optimal across multiple objectives (quality, cost, speed), preventing single-metric gaming
  • Execution trace analysis — the GEPA optimizer reads traces to understand why failures occur, reducing blind mutations
  • Human review — evolution runs produce diffs that can be reviewed before deployment
  • Rollback — skills are versioned; previous versions can be restored via hermes skills reset <name> --restore

Unattended evolution

Running self-evolution unattended in production is not recommended at v0.9.0. Review generated diffs before deploying evolved skills to production agents.

Plugin Security

Plugins execute arbitrary Python in the agent process with no sandboxing. Risks include:

  • Data exfiltration (reading .env, session database, filesystem)
  • Code injection (registering malicious tools)
  • Denial of service (blocking the agent loop)

Mitigations:

  • Plugins must be explicitly placed in ~/.hermes/plugins/ or .hermes/plugins/ by the user
  • Hub-installed skills are scanned on install (hermes skills install runs a security scan)
  • Periodic re-scanning is available via hermes skills audit
  • There is no runtime sandbox for plugins -- trust is placement-based

Network Security

API Server Binding

The API server gives full access to Hermes's toolset, including terminal commands. The API_SERVER_KEY is required when binding to a non-loopback address:

# Safe: loopback only (default)
hermes api --host 127.0.0.1

# Requires API_SERVER_KEY for non-loopback
hermes api --host 0.0.0.0

Keep API_SERVER_CORS_ORIGINS narrow to control browser access.

Web Dashboard

The web dashboard reads and writes ~/.hermes/.env. It binds to 127.0.0.1 by default.

Dashboard exposure

Binding the dashboard to 0.0.0.0 exposes your API keys and credentials to anyone on your network. The dashboard has no built-in authentication. Use a reverse proxy with TLS and authentication if remote access is required.

Gateway Network Exposure

Platform adapters use outbound connections (long polling, WebSocket) and do not require inbound port exposure in most configurations. Exceptions:

  • Webhook mode (Telegram, Feishu, WeCom) requires an inbound HTTPS endpoint
  • API server adapter requires a listening port

For webhook-based platforms, deploy behind a reverse proxy with TLS termination.

Sources