hermes-plugin-guard 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hermes_plugin_guard-0.1.3/CHANGELOG.md +86 -0
- hermes_plugin_guard-0.1.3/CODE_OF_CONDUCT.md +46 -0
- hermes_plugin_guard-0.1.3/CONTRIBUTING.md +71 -0
- hermes_plugin_guard-0.1.3/LICENSE +21 -0
- hermes_plugin_guard-0.1.3/MANIFEST.in +7 -0
- hermes_plugin_guard-0.1.3/PKG-INFO +292 -0
- hermes_plugin_guard-0.1.3/README.md +260 -0
- hermes_plugin_guard-0.1.3/SECURITY.md +54 -0
- hermes_plugin_guard-0.1.3/docs/social-card.svg +81 -0
- hermes_plugin_guard-0.1.3/pyproject.toml +81 -0
- hermes_plugin_guard-0.1.3/setup.cfg +4 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/__init__.py +7 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/__main__.py +3 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/catalog.py +252 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/cli.py +143 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/dependency_scan.py +264 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/manifest.py +620 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/models.py +126 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/python_scan.py +1640 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/reporters.py +207 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/scanner.py +338 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard/secret_scan.py +113 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/PKG-INFO +292 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/SOURCES.txt +46 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/dependency_links.txt +1 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/entry_points.txt +3 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/requires.txt +7 -0
- hermes_plugin_guard-0.1.3/src/hermes_plugin_guard.egg-info/top_level.txt +1 -0
- hermes_plugin_guard-0.1.3/tests/conftest.py +48 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/LICENSE +1 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/SECURITY.md +3 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/__init__.py +40 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/credentials.json +3 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/plugin.yaml +6 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/requirements.txt +2 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/risky_plugin/tests/fixture_check.py +5 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/safe_plugin/LICENSE +1 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/safe_plugin/SECURITY.md +3 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/safe_plugin/__init__.py +21 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/safe_plugin/plugin.yaml +11 -0
- hermes_plugin_guard-0.1.3/tests/fixtures/safe_plugin/tests/fixture_check.py +5 -0
- hermes_plugin_guard-0.1.3/tests/test_cli.py +126 -0
- hermes_plugin_guard-0.1.3/tests/test_dependency_scan.py +154 -0
- hermes_plugin_guard-0.1.3/tests/test_manifest.py +452 -0
- hermes_plugin_guard-0.1.3/tests/test_python_scan.py +755 -0
- hermes_plugin_guard-0.1.3/tests/test_reporters.py +197 -0
- hermes_plugin_guard-0.1.3/tests/test_scanner.py +424 -0
- hermes_plugin_guard-0.1.3/tests/test_secret_scan.py +47 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
6
|
+
uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.3] - 2026-07-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Recognize pip-distributed Hermes plugins declared through
|
|
15
|
+
`[project.entry-points."hermes_agent.plugins"]`, including multiple entry points per package,
|
|
16
|
+
without requiring `plugin.yaml`; validate entry-point and dashboard declarations additively when
|
|
17
|
+
a plugin ships more than one supported declaration.
|
|
18
|
+
- Inspect `plugin.yaml` `pip_dependencies` and flag remote installer commands that download and
|
|
19
|
+
pipe mutable scripts directly to a shell as `HPG204`.
|
|
20
|
+
- Report `register_middleware()` as a privileged execution surface.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Match the current Hermes contracts for `optional_env`, exclusive memory-provider lifecycle
|
|
25
|
+
hooks, dashboard manifest required fields, and dashboard entry bundles.
|
|
26
|
+
- Stop treating Python docstrings as sensitive-path findings, and resolve literal `__import__()`
|
|
27
|
+
targets so their process and network behavior is reported in addition to `HPG101`.
|
|
28
|
+
- Ignore a Python distribution's own extras when checking third-party dependency bounds and avoid
|
|
29
|
+
secret-name findings for metadata variables ending in `_URL`, `_URI`, `_SCOPE`, `_ID`, `_NAME`,
|
|
30
|
+
or `_PATH`.
|
|
31
|
+
- Bound every untrusted manifest parse by size and depth, including the dependency pass.
|
|
32
|
+
|
|
33
|
+
## [0.1.2] - 2026-07-25
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `HPG112` inventories concrete outbound Python network calls without executing code, resolving
|
|
38
|
+
DNS, or making requests.
|
|
39
|
+
- Destination-aware findings redact credentials, paths, queries, fragments, headers, and payloads,
|
|
40
|
+
and distinguish loopback, encrypted, cleartext, and link-local/cloud-metadata targets.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Recognize the current Hermes `pre_verify` and Kanban task hooks so valid plugin manifests do not
|
|
45
|
+
receive `HPG006` compatibility findings.
|
|
46
|
+
|
|
47
|
+
## [0.1.1] - 2026-07-23
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- Five-minute beta-test quickstart and a structured feedback issue form.
|
|
52
|
+
- A reproducible 20-second terminal demo for the README and community posts.
|
|
53
|
+
- Opt-in, tokenless PyPI Trusted Publishing workflow for published GitHub releases, including
|
|
54
|
+
distribution attestations and a safe configuration gate.
|
|
55
|
+
- Maintainer release checklist for the one-time PyPI and GitHub environment setup.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Ignore tests, fixtures, caches, virtual environments, and generated directories during default
|
|
60
|
+
behavior and secret scanning so development-only samples do not dominate plugin reports.
|
|
61
|
+
- Recognize nested plugin repositories and official dashboard-only plugins that use
|
|
62
|
+
`dashboard/manifest.json`.
|
|
63
|
+
- Update the reusable GitHub Action and documentation examples to current Node 24-based action
|
|
64
|
+
releases.
|
|
65
|
+
- Clarified that scans remain local, do not execute target plugin code, make no network requests,
|
|
66
|
+
include no telemetry, and upload neither source nor results.
|
|
67
|
+
- Updated installation and GitHub Action examples for the v0.1.1 release.
|
|
68
|
+
|
|
69
|
+
## [0.1.0] - 2026-07-23
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- Static discovery and validation of one plugin or a repository of plugins.
|
|
74
|
+
- Manifest checks for metadata, plugin kind, entry point, declared environment, and hook drift.
|
|
75
|
+
- AST-based checks for high-risk Python capabilities and load-time behavior.
|
|
76
|
+
- Heuristic scanning for committed secret material.
|
|
77
|
+
- Remote-dependency pinning and version-bound checks.
|
|
78
|
+
- Human-readable, JSON, SARIF, and GitHub annotation output.
|
|
79
|
+
- Configurable failure thresholds and per-rule command-line exclusions.
|
|
80
|
+
- Composite GitHub Action and pinned continuous-integration workflow.
|
|
81
|
+
|
|
82
|
+
[Unreleased]: https://github.com/mauricemohr88-debug/hermes-plugin-guard/compare/v0.1.3...HEAD
|
|
83
|
+
[0.1.3]: https://github.com/mauricemohr88-debug/hermes-plugin-guard/compare/v0.1.2...v0.1.3
|
|
84
|
+
[0.1.2]: https://github.com/mauricemohr88-debug/hermes-plugin-guard/compare/v0.1.1...v0.1.2
|
|
85
|
+
[0.1.1]: https://github.com/mauricemohr88-debug/hermes-plugin-guard/compare/v0.1.0...v0.1.1
|
|
86
|
+
[0.1.0]: https://github.com/mauricemohr88-debug/hermes-plugin-guard/releases/tag/v0.1.0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Code of conduct
|
|
2
|
+
|
|
3
|
+
## Our commitment
|
|
4
|
+
|
|
5
|
+
We are committed to making participation in this project a respectful, harassment-free
|
|
6
|
+
experience for everyone, regardless of age, body size, disability, ethnicity, sex
|
|
7
|
+
characteristics, gender identity and expression, level of experience, education,
|
|
8
|
+
socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual
|
|
9
|
+
identity and orientation.
|
|
10
|
+
|
|
11
|
+
## Expected behavior
|
|
12
|
+
|
|
13
|
+
Examples of behavior that supports a healthy community include:
|
|
14
|
+
|
|
15
|
+
- using welcoming and inclusive language;
|
|
16
|
+
- giving specific, technical, and empathetic feedback;
|
|
17
|
+
- respecting differing viewpoints and experience;
|
|
18
|
+
- accepting responsibility, apologizing, and learning from mistakes;
|
|
19
|
+
- focusing on what is best for users and the wider community.
|
|
20
|
+
|
|
21
|
+
Unacceptable behavior includes harassment, threats, discriminatory language, sexualized
|
|
22
|
+
attention, deliberate intimidation, publishing another person's private information, and
|
|
23
|
+
sustained disruption of project discussion.
|
|
24
|
+
|
|
25
|
+
## Scope
|
|
26
|
+
|
|
27
|
+
This code applies in project spaces and when someone publicly represents the project, including
|
|
28
|
+
issues, pull requests, reviews, discussions, release channels, and community events.
|
|
29
|
+
|
|
30
|
+
## Enforcement
|
|
31
|
+
|
|
32
|
+
Project maintainers may edit, remove, or reject contributions and may temporarily or permanently
|
|
33
|
+
restrict participation when behavior violates these standards. Enforcement decisions should be
|
|
34
|
+
proportionate, documented privately, and protect the privacy and safety of people who report an
|
|
35
|
+
incident.
|
|
36
|
+
|
|
37
|
+
Report conduct concerns privately through the repository's
|
|
38
|
+
[security advisory form](https://github.com/mauricemohr88-debug/hermes-plugin-guard/security/advisories/new)
|
|
39
|
+
and start the title with `Code of Conduct`. Do not include sensitive personal information beyond
|
|
40
|
+
what is needed to understand the incident. Reports will be reviewed promptly and as
|
|
41
|
+
confidentially as practical.
|
|
42
|
+
|
|
43
|
+
## Attribution
|
|
44
|
+
|
|
45
|
+
This policy is informed by the [Contributor Covenant, version
|
|
46
|
+
2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping make Hermes plugin review more repeatable. Small, focused pull requests are
|
|
4
|
+
easiest to review.
|
|
5
|
+
|
|
6
|
+
## Set up a development environment
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/mauricemohr88-debug/hermes-plugin-guard.git
|
|
10
|
+
cd hermes-plugin-guard
|
|
11
|
+
python3.11 -m venv .venv
|
|
12
|
+
source .venv/bin/activate
|
|
13
|
+
python -m pip install -e ".[dev]"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Run the same checks as CI:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
ruff check .
|
|
20
|
+
ruff format --check .
|
|
21
|
+
pytest --cov=hermes_plugin_guard --cov-report=term-missing
|
|
22
|
+
python -m build
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To apply formatting locally:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ruff check --fix .
|
|
29
|
+
ruff format .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Propose a change
|
|
33
|
+
|
|
34
|
+
1. Search existing issues and pull requests for related work.
|
|
35
|
+
2. Open an issue first for broad behavior changes or rule-ID changes.
|
|
36
|
+
3. Create a focused branch and keep unrelated formatting out of the change.
|
|
37
|
+
4. Add or update tests.
|
|
38
|
+
5. Update the README and changelog when user-visible behavior changes.
|
|
39
|
+
6. Explain the threat scenario, expected output, and false-positive tradeoff in the pull request.
|
|
40
|
+
|
|
41
|
+
## Detection-rule expectations
|
|
42
|
+
|
|
43
|
+
Rules are a public interface. New or changed rules should:
|
|
44
|
+
|
|
45
|
+
- use the next stable `HPG` identifier and keep existing IDs unchanged;
|
|
46
|
+
- describe observable behavior rather than label a plugin as malicious;
|
|
47
|
+
- include a concise remediation;
|
|
48
|
+
- report the narrowest useful file and line location;
|
|
49
|
+
- have a positive fixture that triggers and a nearby negative fixture that does not;
|
|
50
|
+
- avoid importing, executing, resolving, or installing target plugin code;
|
|
51
|
+
- stay deterministic and avoid network access;
|
|
52
|
+
- document important blind spots and expected false positives.
|
|
53
|
+
|
|
54
|
+
Prefer Python AST inspection over regular expressions when syntax matters. Secret detection and
|
|
55
|
+
non-Python metadata checks may use bounded text matching. Scanners must skip symlinks and handle
|
|
56
|
+
malformed or unexpectedly encoded input without crashing the entire run.
|
|
57
|
+
|
|
58
|
+
## Tests
|
|
59
|
+
|
|
60
|
+
Use synthetic values in fixtures. Never commit real credentials, private plugin code, or a token
|
|
61
|
+
that resembles a live credential more closely than the test requires.
|
|
62
|
+
|
|
63
|
+
Tests should cover exit behavior and every supported output format when a change touches reporting
|
|
64
|
+
or the CLI. Keep ordering deterministic so generated JSON and SARIF are stable.
|
|
65
|
+
|
|
66
|
+
## Reporting security issues
|
|
67
|
+
|
|
68
|
+
Follow [SECURITY.md](SECURITY.md). Please do not demonstrate an exploitable scanner issue in a
|
|
69
|
+
public issue or pull request before a fix is available.
|
|
70
|
+
|
|
71
|
+
By participating, you agree to follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maurice Mohr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-plugin-guard
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Static, no-execution security checks for Hermes Agent plugins
|
|
5
|
+
Author: Maurice Mohr
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mauricemohr88-debug/hermes-plugin-guard
|
|
8
|
+
Project-URL: Issues, https://github.com/mauricemohr88-debug/hermes-plugin-guard/issues
|
|
9
|
+
Project-URL: Repository, https://github.com/mauricemohr88-debug/hermes-plugin-guard
|
|
10
|
+
Project-URL: Security, https://github.com/mauricemohr88-debug/hermes-plugin-guard/security/policy
|
|
11
|
+
Keywords: hermes-agent,plugins,security,static-analysis,sarif
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: PyYAML<7,>=6.0.2
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build<2,>=1.2; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest<10,>=8.3; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov<8,>=6; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff<1,>=0.11; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Hermes Plugin Guard
|
|
34
|
+
|
|
35
|
+
[](https://github.com/mauricemohr88-debug/hermes-plugin-guard/actions/workflows/ci.yml)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
[](pyproject.toml)
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
Review a Hermes Agent plugin before you enable it.
|
|
42
|
+
|
|
43
|
+
Hermes Plugin Guard (`hpg`) is a local static scanner for
|
|
44
|
+
[NousResearch Hermes Agent](https://github.com/NousResearch/hermes-agent) plugins. It
|
|
45
|
+
checks plugin manifests, Python source, dependency declarations, likely secret material, and
|
|
46
|
+
basic repository hygiene. Target plugin code is read as data: it is never imported or executed.
|
|
47
|
+
|
|
48
|
+
This is an unofficial community project. It is not affiliated with, endorsed by, or maintained
|
|
49
|
+
by Nous Research.
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
## Five-minute beta test
|
|
54
|
+
|
|
55
|
+
If you maintain or use a Hermes plugin, one local scan is enough to help improve the rules.
|
|
56
|
+
Python 3.11 or newer and [pipx](https://pipx.pypa.io/stable/) are required.
|
|
57
|
+
|
|
58
|
+
1. Install the v0.1.3 release directly from GitHub:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pipx install \
|
|
62
|
+
"git+https://github.com/mauricemohr88-debug/hermes-plugin-guard.git@v0.1.3"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
2. Scan your plugin without failing the command on findings:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
hpg scan /absolute/path/to/your-plugin --fail-on none
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
3. Send a short
|
|
72
|
+
[beta-test report](https://github.com/mauricemohr88-debug/hermes-plugin-guard/issues/new?template=beta-test.yml)
|
|
73
|
+
with the rule IDs that were useful, noisy, or missing. A public plugin URL is helpful but not
|
|
74
|
+
required.
|
|
75
|
+
|
|
76
|
+
The scan stays on your computer. `hpg` reads target files as data, does not import or execute
|
|
77
|
+
target plugin code, makes no network requests, includes no telemetry, and uploads neither source
|
|
78
|
+
code nor results. Do not paste private code, credentials, or unsanitized paths into a public issue.
|
|
79
|
+
|
|
80
|
+
Once v0.1.3 is visible on
|
|
81
|
+
[PyPI](https://pypi.org/project/hermes-plugin-guard/), the shorter installation command is:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pipx install hermes-plugin-guard
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Already installed? Use `pipx upgrade hermes-plugin-guard` for a PyPI installation, or reinstall
|
|
88
|
+
the tagged GitHub URL above.
|
|
89
|
+
|
|
90
|
+
## Why this exists
|
|
91
|
+
|
|
92
|
+
Hermes plugins are Python extensions, not isolated data files. A third-party plugin can register
|
|
93
|
+
tools and hooks and can run with the permissions of the Hermes process. Code review remains the
|
|
94
|
+
most important control; `hpg` adds a fast, repeatable first pass before enablement and in CI.
|
|
95
|
+
|
|
96
|
+
The scanner is designed to make high-risk patterns visible, including:
|
|
97
|
+
|
|
98
|
+
- direct subprocess calls that bypass Hermes' terminal-tool approval path;
|
|
99
|
+
- dynamic execution and unsafe deserialization;
|
|
100
|
+
- sensitive-path access, destructive filesystem operations, and disabled TLS verification;
|
|
101
|
+
- all-interface listeners, networking capability, concrete outbound calls with redacted
|
|
102
|
+
destinations, and undeclared secret environment variables;
|
|
103
|
+
- privileged registration and middleware surfaces, plus work performed during import or
|
|
104
|
+
registration;
|
|
105
|
+
- likely committed credentials, mutable remote dependencies, and remote scripts piped to shells;
|
|
106
|
+
- plugin declaration drift, missing tests, and missing project policies.
|
|
107
|
+
|
|
108
|
+
## Install
|
|
109
|
+
|
|
110
|
+
Python 3.11 or newer is required.
|
|
111
|
+
|
|
112
|
+
Install the current release directly from GitHub with
|
|
113
|
+
[pipx](https://pipx.pypa.io/stable/) (recommended for command-line tools):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pipx install \
|
|
117
|
+
"git+https://github.com/mauricemohr88-debug/hermes-plugin-guard.git@v0.1.3"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
After the release is published to
|
|
121
|
+
[PyPI](https://pypi.org/project/hermes-plugin-guard/), install it by package name:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pipx install hermes-plugin-guard
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Or install from a local checkout:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
git clone https://github.com/mauricemohr88-debug/hermes-plugin-guard.git
|
|
131
|
+
cd hermes-plugin-guard
|
|
132
|
+
python -m pip install .
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Both `hpg` and `hermes-plugin-guard` invoke the same command.
|
|
136
|
+
|
|
137
|
+
## Usage
|
|
138
|
+
|
|
139
|
+
Scan one plugin directory:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
hpg scan /path/to/my-plugin
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Scan a repository containing multiple plugins and fail when a high or critical finding exists:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
hpg scan /path/to/plugins-repository --fail-on high
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The scanner recognizes directory plugins using `plugin.yaml`, dashboard-only plugins using
|
|
152
|
+
`dashboard/manifest.json`, and pip-distributed plugins using
|
|
153
|
+
`[project.entry-points."hermes_agent.plugins"]` in `pyproject.toml`.
|
|
154
|
+
|
|
155
|
+
Write machine-readable results:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
hpg scan ./my-plugin --format json --output hpg.json
|
|
159
|
+
hpg scan ./my-plugin --format sarif --output hpg.sarif
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Show GitHub workflow annotations:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
hpg scan ./my-plugin --format github
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Exclude a reviewed rule for one invocation:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
hpg scan ./my-plugin --exclude HPG106 --exclude HPG203
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
List the complete rule catalog and remediation guidance:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
hpg rules
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The default failure threshold is `high`. Use `--fail-on critical`, `high`, `medium`,
|
|
181
|
+
`low`, `info`, or `none` to set policy. Exit code `0` means no finding reached the selected
|
|
182
|
+
threshold, `1` means the policy threshold was reached, and `2` indicates an invocation or scan
|
|
183
|
+
error.
|
|
184
|
+
|
|
185
|
+
## Output
|
|
186
|
+
|
|
187
|
+
`hpg` keeps rule IDs stable so findings can be discussed and tracked across runs.
|
|
188
|
+
|
|
189
|
+
| Format | Intended use |
|
|
190
|
+
| --- | --- |
|
|
191
|
+
| `text` | Human-readable local review (default) |
|
|
192
|
+
| `github` | File and line annotations in GitHub Actions logs |
|
|
193
|
+
| `json` | Automation, baselines, and custom reporting |
|
|
194
|
+
| `sarif` | SARIF-compatible code-scanning consumers |
|
|
195
|
+
|
|
196
|
+
JSON includes the scan root, plugin and file counts, severity totals, sorted findings, and a
|
|
197
|
+
stable fingerprint for each finding. SARIF includes rule metadata and source locations. Output is
|
|
198
|
+
deterministic for unchanged inputs.
|
|
199
|
+
|
|
200
|
+
## GitHub Actions
|
|
201
|
+
|
|
202
|
+
The repository includes a composite action:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
name: Plugin security
|
|
206
|
+
|
|
207
|
+
on:
|
|
208
|
+
pull_request:
|
|
209
|
+
|
|
210
|
+
permissions:
|
|
211
|
+
contents: read
|
|
212
|
+
|
|
213
|
+
jobs:
|
|
214
|
+
guard:
|
|
215
|
+
runs-on: ubuntu-latest
|
|
216
|
+
steps:
|
|
217
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
218
|
+
with:
|
|
219
|
+
persist-credentials: false
|
|
220
|
+
- uses: mauricemohr88-debug/hermes-plugin-guard@v0.1.3
|
|
221
|
+
with:
|
|
222
|
+
path: path/to/plugin
|
|
223
|
+
fail-on: high
|
|
224
|
+
format: github
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
For stronger supply-chain controls, pin `hermes-plugin-guard` to a reviewed full commit SHA
|
|
228
|
+
instead of a moving tag.
|
|
229
|
+
|
|
230
|
+
## Rules at a glance
|
|
231
|
+
|
|
232
|
+
| IDs | Area | Examples |
|
|
233
|
+
| --- | --- | --- |
|
|
234
|
+
| `HPG001`–`HPG006` | Declaration | Missing or invalid declarations, unknown kind, entry point and hook drift |
|
|
235
|
+
| `HPG101`–`HPG112` | Python | Execution, deserialization, processes, sensitive paths, network and privileged behavior |
|
|
236
|
+
| `HPG201`–`HPG204` | Supply chain | Likely secrets, mutable dependencies, unbounded versions, remote installers |
|
|
237
|
+
| `HPG301`–`HPG303` | Project | License, security policy, and automated tests |
|
|
238
|
+
|
|
239
|
+
Run `hpg rules` for the current severity, explanation, and suggested remediation for every rule.
|
|
240
|
+
|
|
241
|
+
### Network-egress inventory
|
|
242
|
+
|
|
243
|
+
`HPG106` reports that a plugin imports a network-capable module. `HPG112` is more specific: it
|
|
244
|
+
reports a concrete outbound request or connection and records the statically visible destination.
|
|
245
|
+
The scanner never resolves DNS or makes a request while doing this.
|
|
246
|
+
|
|
247
|
+
Destination evidence is deliberately limited to the scheme, hostname, and port. User information,
|
|
248
|
+
paths, query strings, fragments, headers, and payloads are never copied into a finding. Dynamic or
|
|
249
|
+
relative destinations are reported as `<dynamic destination>`. Loopback calls default to low,
|
|
250
|
+
encrypted external calls to medium, and explicitly cleartext HTTP, FTP, WebSocket, or gRPC and
|
|
251
|
+
link-local/cloud-metadata targets to high. Raw TCP and SMTP stay medium because the protocol may
|
|
252
|
+
upgrade to TLS after connecting.
|
|
253
|
+
|
|
254
|
+
## Threat model
|
|
255
|
+
|
|
256
|
+
The scanner assumes a plugin directory may be untrusted and inspects it without importing its
|
|
257
|
+
Python modules. It aims to catch explicit, statically visible patterns that deserve human review.
|
|
258
|
+
It also helps maintainers enforce a consistent minimum policy in pull requests.
|
|
259
|
+
|
|
260
|
+
Scanning is a review aid, not a sandbox, signature verifier, malware detector, or proof that a
|
|
261
|
+
plugin is safe. Enabling a plugin still grants its code the permissions of the Hermes process.
|
|
262
|
+
Review the source, dependencies, requested environment variables, network destinations, and
|
|
263
|
+
maintainer history before installation.
|
|
264
|
+
|
|
265
|
+
## Limitations
|
|
266
|
+
|
|
267
|
+
- Static analysis cannot reliably resolve dynamically constructed names, paths, commands, or
|
|
268
|
+
network destinations.
|
|
269
|
+
- Egress checks cover common Python HTTP, WebSocket, socket, FTP, SMTP, and gRPC APIs. Calls hidden
|
|
270
|
+
behind dependencies, arbitrary SDK wrappers, native extensions, or dashboard JavaScript can
|
|
271
|
+
require manual review.
|
|
272
|
+
- A finding describes a risky capability or pattern, not necessarily a vulnerability.
|
|
273
|
+
- The absence of findings does not establish safety.
|
|
274
|
+
- Secret matching is heuristic and may produce false positives or miss encoded or split secrets.
|
|
275
|
+
- Dependency checks inspect `requirements*.txt`, `pyproject.toml`, and relevant `plugin.yaml`
|
|
276
|
+
declarations; they do not resolve, download, or audit dependency contents.
|
|
277
|
+
- Symlinks and oversized files are skipped rather than followed or executed.
|
|
278
|
+
- Suppressions are command-line policy choices and should be documented in the consuming project.
|
|
279
|
+
|
|
280
|
+
If a result looks wrong, please open an issue with the smallest safe reproducer. Never attach
|
|
281
|
+
live credentials or private plugin code to a public report.
|
|
282
|
+
|
|
283
|
+
## Development and contributing
|
|
284
|
+
|
|
285
|
+
Contributions are welcome, especially focused detection rules with both positive and negative
|
|
286
|
+
tests. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and design expectations,
|
|
287
|
+
[SECURITY.md](SECURITY.md) for private vulnerability reporting, and
|
|
288
|
+
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community standards.
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT. See [LICENSE](LICENSE).
|