Skip to main content

Hermes Plugin Guard

CI License: MIT Python 3.11+

Hermes Plugin Guard social card

Review a Hermes Agent plugin before you enable it.

Hermes Plugin Guard (hpg) is a local static scanner for NousResearch Hermes Agent plugins. It checks plugin manifests, Python source, dependency declarations, likely secret material, and basic repository hygiene. Target plugin code is read as data: it is never imported or executed.

This is an unofficial community project. It is not affiliated with, endorsed by, or maintained by Nous Research.

20-second CLI demo recorded with Hermes Plugin Guard v0.1.4

Five-minute beta test

If you maintain or use a Hermes plugin, one local scan is enough to help improve the rules. Python 3.11 or newer and pipx are required.

  1. Install the current release from PyPI:

    pipx install hermes-plugin-guard
    
  2. Scan your plugin without failing the command on findings:

    hpg scan /absolute/path/to/your-plugin --fail-on none
    
  3. Send a short beta-test report with the rule IDs that were useful, noisy, or missing. A public plugin URL is helpful but not required.

The standalone hpg scan stays on your computer. It reads target files as data, does not import or execute target plugin code, makes no network requests, includes no telemetry, and uploads neither source code nor results. The optional native Hermes tool has a different, explicitly documented privacy boundary below. Do not paste private code, credentials, or unsanitized paths into a public issue.

Already installed? Use pipx upgrade hermes-plugin-guard. For a reproducible installation directly from the tagged source, install the v0.2.0 GitHub release:

pipx install \
  "git+https://github.com/mauricemohr88-debug/hermes-plugin-guard.git@v0.2.0"

Why this exists

Hermes plugins are Python extensions, not isolated data files. A third-party plugin can register tools and hooks and can run with the permissions of the Hermes process. Code review remains the most important control; hpg adds a fast, repeatable first pass before enablement and in CI.

The scanner is designed to make high-risk patterns visible, including:

  • direct subprocess calls that bypass Hermes' terminal-tool approval path;
  • dynamic execution and unsafe deserialization;
  • sensitive-path access, destructive filesystem operations, and disabled TLS verification;
  • all-interface listeners, networking capability, concrete outbound calls with redacted destinations, and undeclared secret environment variables;
  • privileged registration and middleware surfaces, plus work performed during import or registration;
  • likely committed credentials, mutable remote dependencies, and remote scripts piped to shells;
  • plugin declaration drift, missing tests, and missing project policies.

Install

Python 3.11 or newer is required.

Install the current release from PyPI with pipx (recommended for command-line tools):

pipx install hermes-plugin-guard

Alternatively, install reproducibly from the tagged GitHub source:

pipx install \
  "git+https://github.com/mauricemohr88-debug/hermes-plugin-guard.git@v0.2.0"

Or install from a local checkout:

git clone https://github.com/mauricemohr88-debug/hermes-plugin-guard.git
cd hermes-plugin-guard
python -m pip install .

Both hpg and hermes-plugin-guard invoke the same command.

Native Hermes v0.20 integration

Hermes Plugin Guard can also be installed as a native, review-only Hermes plugin from Git. Keep it disabled during installation, then enable the guard itself without granting tool-override permission:

hermes plugins install mauricemohr88-debug/hermes-plugin-guard --no-enable
hermes plugins enable hermes-plugin-guard --no-allow-tool-override

In a new Hermes process you can use the operator CLI:

hermes plugin-guard rules
hermes plugin-guard scan /path/to/a/plugin --fail-on high

The safest manual review sequence for another Git plugin is:

hermes plugins install owner/repository --no-enable
hermes plugin-guard installed plugin-name --fail-on high
hermes plugins enable plugin-name --no-allow-tool-override

Hermes also receives one read-only model tool, plugin_guard_review_candidate. It accepts only an installed plugin key below HERMES_HOME/plugins, refuses currently enabled plugins, applies fixed high-severity policy, and returns at most 20 findings. The strict native path scans runtime-capable directories such as tests, build, and generated, rejects unsupported executable binaries, and runs the analyzer in a single resource-bounded worker. Its response contains only rule IDs, severity, opaque location IDs, bounded line numbers, and bounded counts; it omits filenames, source, finding messages, evidence, dependency strings, secrets, internal tree digests, and absolute paths. That bounded response becomes part of the active Hermes conversation and may therefore be sent to the configured model provider. Exclusive, model-provider, and Hermes-detected legacy memory or cron-scheduler plugins use separate activation paths. Those candidates are rejected by this tool rather than being incorrectly described as disabled.

This integration does not intercept or replace Hermes' native install, update, enable, or load paths. Hermes v0.20 has no third-party plugin-admission hook, so the guard cannot honestly enforce a scan before every activation. The native surface is a convenient review step; the operator still makes the activation decision. Its private before/after digest detects endpoint changes during a review, but it is not an atomic filesystem snapshot or sandbox. A generic upstream admission-policy proposal is already registered with the Hermes plugin-interface tracker.

Usage

Scan one plugin directory:

hpg scan /path/to/my-plugin

Scan a repository containing multiple plugins and fail when a high or critical finding exists:

hpg scan /path/to/plugins-repository --fail-on high

The scanner recognizes directory plugins using plugin.yaml, dashboard-only plugins using dashboard/manifest.json, and pip-distributed plugins using [project.entry-points."hermes_agent.plugins"] in pyproject.toml.

Write machine-readable results:

hpg scan ./my-plugin --format json --output hpg.json
hpg scan ./my-plugin --format sarif --output hpg.sarif

Show GitHub workflow annotations:

hpg scan ./my-plugin --format github

Exclude a reviewed rule for one invocation:

hpg scan ./my-plugin --exclude HPG106 --exclude HPG203

List the complete rule catalog and remediation guidance:

hpg rules

The default failure threshold is high. Use --fail-on critical, high, medium, low, info, or none to set policy. Exit code 0 means no finding reached the selected threshold, 1 means the policy threshold was reached, and 2 indicates an invocation or scan error.

Output

hpg keeps rule IDs stable so findings can be discussed and tracked across runs.

Format Intended use
text Human-readable local review (default)
github File and line annotations in GitHub Actions logs
json Automation, baselines, and custom reporting
sarif SARIF-compatible code-scanning consumers

JSON includes the scan root, plugin and file counts, severity totals, sorted findings, and a stable fingerprint for each finding. SARIF includes rule metadata and source locations. Output is deterministic for unchanged inputs.

GitHub Actions

The repository includes a composite action:

name: Plugin security

on:
  pull_request:

permissions:
  contents: read

jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - uses: mauricemohr88-debug/hermes-plugin-guard@v0.2.0
        with:
          path: path/to/plugin
          fail-on: high
          format: github

For stronger supply-chain controls, pin hermes-plugin-guard to a reviewed full commit SHA instead of a moving tag.

Rules at a glance

IDs Area Examples
HPG001HPG006 Declaration Missing or invalid declarations, unknown kind, entry point and hook drift
HPG101HPG112 Python Execution, deserialization, processes, sensitive paths, network and privileged behavior
HPG201HPG204 Supply chain Likely secrets, mutable dependencies, unbounded versions, remote installers
HPG301HPG303 Project License, security policy, and automated tests

Run hpg rules for the current severity, explanation, and suggested remediation for every rule.

Network-egress inventory

HPG106 reports that a plugin imports a network-capable module. HPG112 is more specific: it reports a concrete outbound request or connection and records the statically visible destination. The scanner never resolves DNS or makes a request while doing this.

Destination evidence is deliberately limited to the scheme, hostname, and port. User information, paths, query strings, fragments, headers, and payloads are never copied into a finding. Dynamic or relative destinations are reported as <dynamic destination>. Loopback calls default to low, encrypted external calls to medium, and explicitly cleartext HTTP, FTP, WebSocket, or gRPC and link-local/cloud-metadata targets to high. Raw TCP and SMTP stay medium because the protocol may upgrade to TLS after connecting.

Threat model

The scanner assumes a plugin directory may be untrusted and inspects it without importing its Python modules. It aims to catch explicit, statically visible patterns that deserve human review. It also helps maintainers enforce a consistent minimum policy in pull requests.

Scanning is a review aid, not a sandbox, signature verifier, malware detector, or proof that a plugin is safe. Enabling a plugin still grants its code the permissions of the Hermes process. Review the source, dependencies, requested environment variables, network destinations, and maintainer history before installation.

Limitations

  • Static analysis cannot reliably resolve dynamically constructed names, paths, commands, or network destinations.
  • Egress checks cover common Python HTTP, WebSocket, socket, FTP, SMTP, and gRPC APIs. Calls hidden behind dependencies, arbitrary SDK wrappers, native extensions, or dashboard JavaScript can require manual review.
  • A finding describes a risky capability or pattern, not necessarily a vulnerability.
  • The absence of findings does not establish safety.
  • Secret matching is heuristic and may produce false positives or miss encoded or split secrets.
  • Dependency checks inspect requirements*.txt, pyproject.toml, and relevant plugin.yaml declarations; they do not resolve, download, or audit dependency contents.
  • Symlinks and oversized files are skipped rather than followed or executed.
  • Suppressions are command-line policy choices and should be documented in the consuming project.

If a result looks wrong, please open an issue with the smallest safe reproducer. Never attach live credentials or private plugin code to a public report.

Development and contributing

Contributions are welcome, especially focused detection rules with both positive and negative tests. See CONTRIBUTING.md for setup and design expectations, SECURITY.md for private vulnerability reporting, and CODE_OF_CONDUCT.md for community standards.

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_plugin_guard-0.2.0.tar.gz (77.2 kB view details)

Uploaded Source

Built Distribution

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

hermes_plugin_guard-0.2.0-py3-none-any.whl (51.3 kB view details)

Uploaded Python 3

File details

Details for the file hermes_plugin_guard-0.2.0.tar.gz.

File metadata

  • Download URL: hermes_plugin_guard-0.2.0.tar.gz
  • Upload date:
  • Size: 77.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hermes_plugin_guard-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0259ba5976520e442d30bc7a806fbcca2e60287067038dd2290e1e1a7d2f1a55
MD5 ac0ba69ef2943bdaca437e0b6d26b63b
BLAKE2b-256 97c2143b8e3683928be1a93267f7e4d008e2a282d46320a7795aa29230e0a0b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_plugin_guard-0.2.0.tar.gz:

Publisher: publish.yml on mauricemohr88-debug/hermes-plugin-guard

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_plugin_guard-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for hermes_plugin_guard-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 15a4549db39cc806b3786fb5fc16105f2263f655d314bba393649c236822afa1
MD5 58f18e596aa62691cca268724273f82c
BLAKE2b-256 65be7d22bb9861cc7a0496f0d20360b037cb1087ba37d474f904412ef534171e

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_plugin_guard-0.2.0-py3-none-any.whl:

Publisher: publish.yml on mauricemohr88-debug/hermes-plugin-guard

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page