Skip to main content

hermes-sfw

CI License: MIT Python 3.11+

Socket Firewall Free plugin for Hermes Agent.

Block known malicious dependencies during supported dependency operations. Route those operations through sfw for automatic protection — no API key, no config.

sfw action=run command="npm install express"
sfw action=status

quick start

Requires Python 3.11+, Hermes Agent, and the Socket Firewall Free sfw CLI.

Install the prerequisite and the plugin:

npm i -g sfw
python -m pip install hermes-sfw
hermes plugins enable hermes-sfw --no-allow-tool-override

Run /reset or restart Hermes, then verify without installing a throwaway dependency:

sfw --version
python -m pip show hermes-sfw
hermes plugins list --enabled --plain

Inside Hermes:

sfw action=status

If Hermes cannot see the package, install it with the Python environment that owns the hermes executable. See AGENTS.md.

For source development:

git clone https://github.com/TheEpTic/hermes-plugins.git
cd hermes-plugins/hermes-sfw
./deploy.sh
hermes plugins enable hermes-sfw --no-allow-tool-override

Run /reset or restart Hermes after changing the source tree.

features

sfw run — execute commands

Run supported dependency operations through sfw. Known malicious packages are blocked automatically.

# Install a package
sfw action=run command="npm install express"

# Uninstall
sfw action=run command="npm uninstall lodash"

# Python packages
sfw action=run command="pip install flask"
sfw action=run command="uv pip install -r requirements.txt"

# Rust crates
sfw action=run command="cargo add serde"

# With verbose output
sfw action=run command="pnpm add -D vitest" verbose=true

# In a specific directory
sfw action=run command="npm install" workdir="/path/to/project"

Supported package managers: npm, yarn, and pnpm for JavaScript/TypeScript; pip, pip3, and uv for Python; cargo for Rust. Each manager is restricted to dependency operations — for example npm install, npm ci, npm uninstall, and npm update are accepted, but runner-style subcommands like npm run are not. npx, rustup, and runner-style subcommands are intentionally blocked because they can execute arbitrary programs.

Blocked packages: When sfw detects a malicious package, the install is blocked and the package name is returned in the response. Blocked and installed indicators are parsed from sfw output and returned as blocked and installed lists in the result, alongside success, command, exit_code, stdout, and stderr:

🔴 blocked malicious-pkg
blocked: evil-trojan
🟢 installed express
added 5 packages

Non-package-manager commands (like cat, rm, curl) are rejected by the prefix allowlist, and commands longer than 1,024 characters are rejected outright.

Output truncation: Output exceeding 10,000 characters is intentionally truncated with a size note. The discarded suffix is not returned in another field.

automatic terminal enforcement

When enabled, the plugin watches Hermes terminal calls. A supported dependency operation such as npm install, uv pip install, or cargo fetch is rewritten before execution to invoke the resolved sfw binary:

terminal command: npm install express
executed command: /home/user/.local/share/pnpm/bin/sfw npm install express

The model does not need to notice a block or issue a second tool call. Unsupported package-manager forms, shell-prefixed calls (cd app && npm install, sudo npm install), malformed commands, and manager paths are blocked before raw execution. Non-package-manager terminal commands are unaffected.

The hook only runs when Hermes exposes pre_tool_call hooks. Set HERMES_SFW_ENFORCE_DIRECT=off before starting Hermes only when you deliberately want to bypass automatic terminal enforcement. The default is on.

sfw status — check installation

Verify sfw is installed and get the version.

sfw action=status

Returns: installed (bool), version (string), binary (path). version is the sfw binary's own --version output, which can differ from the npm package version you installed — see troubleshooting.

how it works

hermes-sfw is a thin wrapper around the sfw CLI. It:

  1. Validates commands against the strict package-manager operation grammar
  2. Resolves and validates the working directory (if specified)
  3. Executes the command through sfw with timeout protection
  4. Parses stdout/stderr for blocked and installed package indicators
  5. Returns structured JSON with success status, output, and parsed results

The explicit sfw tool executes the manager as an argument vector — never through a shell — so quoting and special characters cannot reach a shell interpreter. Automatic terminal enforcement uses Hermes's modify hook to build a shell-quoted command for the resolved sfw binary, preserving the same manager arguments while preventing the raw package manager from running. Both paths pass through Hermes's dangerous-command approval system and fail closed when that system is unavailable.

binary discovery

The sfw binary is located on demand for every call rather than cached, so an install that happens after the plugin is registered is picked up immediately. Discovery order:

  1. An explicit SFWConfig(sfw_bin=...) path, if configured
  2. sfw on PATH (shutil.which)
  3. Known shim and install locations:
    • ~/.local/share/pnpm/sfw
    • ~/.local/share/pnpm/bin/sfw
    • ~/.local/bin/sfw
    • ~/.npm-global/bin/sfw
    • ~/.cargo/bin/sfw
    • /usr/local/bin/sfw

configuration

All settings live in src/hermes_sfw/manager.py as an SFWConfig dataclass:

Setting Default Description
sfw_bin sfw Path to the sfw binary (a concrete path bypasses PATH and shim discovery)
timeout 300s Max seconds per command

architecture

src/hermes_sfw/
├── __init__.py          # Plugin registration + Hermes hooks
├── manager.py           # SFWManager — command execution + output parsing
├── schemas.py           # Tool schema (what the LLM sees)
├── utils.py             # ok(), err(), require() helpers
├── py.typed             # PEP 561 marker
└── handlers/
    ├── __init__.py
    └── sfw.py           # sfw tool handler

Key design decisions:

  • SFWManager owns all state. No module-level mutable state.
  • Command prefix allowlist prevents arbitrary command execution through sfw.
  • shlex.split() parsing with error handling catches malformed commands early.
  • Output sanitization truncates long outputs to prevent context overflow.
  • OSError errno mapping provides clean error messages without leaking internals.

security

See SECURITY.md for the full boundary.

Defaults you should know about:

  • Only package manager commands are allowed (prefix allowlist: npm, yarn, pnpm, pip, cargo, etc.)
  • Non-package-manager commands (cat, rm, curl, etc.) are rejected
  • Commands run with the permissions of the Hermes agent process
  • Commands pass through Hermes dangerous-command approval checks and fail closed if the approval system is unavailable

hermes-sfw is a dependency guard, not a sandbox. It blocks packages sfw knows are malicious, but package lifecycle scripts (postinstall, etc.) and build backends still run with the permissions of the Hermes process. Use it to reduce known-bad dependencies, not to contain untrusted code.

Hardening applied:

  • Command prefix validation via allowlist before execution
  • Commands are passed as an argument vector without invoking a shell
  • shlex.split() handles quoting and rejects malformed command strings early
  • Working directories are expanded, resolved, and checked to be existing directories
  • Output truncated at 10K chars to prevent context overflow
  • Timeout protection prevents hanging installs

requirements

troubleshooting

Plugin installed but tools are absent

Enable the plugin and reset Hermes:

hermes plugins enable hermes-sfw --no-allow-tool-override
hermes plugins list --enabled --plain

sfw action=status reports installed: false

The binary was not found on PATH or in any known shim location at the moment of the call. Possible causes:

  • sfw was never installed — run npm i -g sfw.
  • sfw was installed into a different environment or user than the one running Hermes. A shell finding sfw does not prove the Hermes process can find it; background shells, systemd services, and containers often have a different PATH.
  • The install happened after Hermes started. Binary discovery is on-demand since 0.2.4, so no restart is required — but if you are on an older version, restart Hermes after installing sfw.

Version looks wrong (status reports a version that differs from the npm package)

sfw action=status reports the version of the sfw binary (sfw --version). The npm package version and the binary's own version are separate layers and can legitimately differ. Check which layer you are looking at before reporting a bug.

Broken shim: sfw exists but every run fails

pnpm-style installs create a wrapper script at the shim path that points at the real sfw.mjs. If that target file is missing or stale, even npm ci can fail and sfw --version may error. Verify the resolved binary from sfw action=status (the binary field), inspect that path, and repair with npm i -g sfw (or your package manager's equivalent) so the shim is regenerated. As a workaround, point SFWConfig(sfw_bin=...) at a known-good binary.

Command rejected with "not allowed"

Only the documented dependency operations are allowed. Runner-style commands, unsupported subcommands, shell-prefixed calls, malformed commands, and manager paths are intentionally blocked so they cannot bypass SFW. Use a documented sfw operation, or set HERMES_SFW_ENFORCE_DIRECT=off only when you deliberately accept raw terminal dependency execution.

Command timeout

Default timeout is 5 minutes (300s). For very large installs, this may not be enough. Override via SFWConfig(timeout=...) when creating the manager.

Output looks truncated

This is intentional. Outputs over 10K characters are truncated to protect context, and the discarded suffix is not retained by the plugin.

development

git clone https://github.com/TheEpTic/hermes-plugins.git
cd hermes-plugins/hermes-sfw
uv sync --extra dev --locked

# Run the gates
uv run pytest
uv run black --check src tests
uv run mypy src

CI runs those gates on Python 3.11, 3.12, and 3.13.

See CONTRIBUTING.md for guidelines.

license

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hermes_sfw-0.2.7.tar.gz (62.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hermes_sfw-0.2.7-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file hermes_sfw-0.2.7.tar.gz.

File metadata

  • Download URL: hermes_sfw-0.2.7.tar.gz
  • Upload date:
  • Size: 62.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hermes_sfw-0.2.7.tar.gz
Algorithm Hash digest
SHA256 64c280c43d2391a901d662d60a9096ecfd14bc7e8bde0b041718008b9523b259
MD5 86febdded9e2820e8a305300d3004544
BLAKE2b-256 9723d1853d70c6eb3c215388e3ff8f84de98d41c4a1bf8b8408f15f656811bb8

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_sfw-0.2.7.tar.gz:

Publisher: pypi-publish-sfw.yml on TheEpTic/hermes-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hermes_sfw-0.2.7-py3-none-any.whl.

File metadata

  • Download URL: hermes_sfw-0.2.7-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hermes_sfw-0.2.7-py3-none-any.whl
Algorithm Hash digest
SHA256 bd7e24e0bb9258f2f704544e43c43900d80b574aa42832ccacf0ceb620ea7e16
MD5 bdc00a0d77e0bd50633216fb2275df45
BLAKE2b-256 7c49c584b50cedbb3f10ab2d729beeb71fa0f6c66b7a82ad7bd4a63b90a7fc84

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_sfw-0.2.7-py3-none-any.whl:

Publisher: pypi-publish-sfw.yml on TheEpTic/hermes-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.12

2 files

0.2.11

2 files

0.2.8

2 files

This release

0.2.7 This release

2 files

0.2.6

2 files

0.2.5

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page