A small security-audit plugin for Hermes Agent.
It gives Hermes one approval-gated security_audit tool for local secret scanning, dependency vulnerability scanning, and static analysis using:
- Gitleaks for leaked secrets and credentials in the current workspace tree
- OSV-Scanner for vulnerable dependencies
- Semgrep CE for static-analysis findings
I built this because I wanted Hermes to be able to run the same security check I use before calling a coding task finished, without handing the model a pile of shell commands or letting scans happen silently in the background.
The plugin is intentionally pretty boring about security:
- Hermes asks for human approval before every audit.
- Scanner commands are launched with
shell=False. - The plugin does not edit the project being scanned.
- Missing tools, timeouts, malformed output, partial Semgrep analysis errors, and unexpected scanner failures are reported as incomplete coverage instead of quietly becoming a pass.
- Gitleaks runs with full redaction, and secret values are never copied into the normalized result.
- Scanner output is bounded while the process is running instead of being allowed to grow without limit in memory.
- Child processes get a cleaned-up environment so Hermes Desktop / Python / terminal variables do not interfere with scanner JSON output.
The final result uses PASS, FAIL, NOT_APPLICABLE, UNRESOLVED, or BLOCKED, so the agent can tell the difference between "clean" and "I could not verify this."
The first real-world test setup was:
- Hermes Agent
v2026.9.14/ Agentv0.21.3 - Windows 11
- Hermes' Python 3.11 runtime
The code itself is platform-neutral, and the test suite runs on Windows and Linux.
Install these separately and make sure they are on PATH:
There are no third-party Python dependencies in the plugin itself, and Hermes does not need to be patched.
Run this in PowerShell, Command Prompt, Windows Terminal, or a normal macOS/Linux shell—anywhere the hermes command works:
hermes plugins install dafka007/hermes-security-audit --enableYou do not need to download the repository yourself when using this command; Hermes fetches the plugin from GitHub and installs it into its plugin area.
Restart Hermes after installation.
Hermes also supports pinning a custom plugin to one exact immutable Git commit. Replace <FULL_COMMIT_SHA> with the full 40-character commit SHA from the release you want:
hermes plugins install dafka007/hermes-security-audit --enable --ref <FULL_COMMIT_SHA>Hermes intentionally requires a full commit SHA for --ref; tags, branches, and abbreviated SHAs are not accepted for pinned installs.
If you prefer not to use the installer command, GitHub's Releases page provides source ZIP and TAR.GZ downloads. The repository's Code → Download ZIP option also works for the current branch.
Extract the repository and place the folder at:
~/.hermes/plugins/hermes-security-audit/
On a normal Windows setup, ~ means your user profile folder, so that is typically equivalent to:
%USERPROFILE%\.hermes\plugins\hermes-security-audit\
Then enable the plugin and restart Hermes:
hermes plugins enable hermes-security-auditTo check that Hermes can discover and load it:
hermes plugins doctor ~/.hermes/plugins/hermes-security-audit --ciAsk Hermes to call the tool with the workspace you want checked. For example:
Use only the security_audit tool.
Run a security audit on exactly this workspace:
C:\path\to\project
Hermes should show an approval prompt before any scanner starts.
A clean result looks roughly like this:
{
"type": "SECURITY_AUDIT",
"overall": "PASS",
"coverage_incomplete": false,
"scanners": {
"gitleaks": {"status": "PASS", "findings": []},
"osv": {"status": "NOT_APPLICABLE", "findings": []},
"semgrep": {"status": "PASS", "findings": []}
}
}OSV-Scanner exit code 128 is treated as NOT_APPLICABLE; OSV documents that code as "no packages found."
The plugin currently uses Gitleaks' dir scan mode. That checks the files in the workspace tree being audited; it does not scan the repository's full Git commit history. Historical secret scanning may be added separately in the future so it can have its own scope and performance expectations.
Normally the plugin just uses the scanner executables found on PATH. These environment variables are available when you need something different:
| Variable | Purpose |
|---|---|
HSA_GITLEAKS |
Gitleaks executable path/name |
HSA_OSV_SCANNER |
OSV-Scanner executable path/name |
HSA_SEMGREP |
Semgrep executable path/name |
HSA_SEMGREP_CONFIG |
Semgrep rules/config source; defaults to auto |
HSA_TIMEOUT_SECONDS |
Per-scanner timeout, 10–1800 seconds; default 300 |
For example, to use a local Semgrep rules directory on Windows:
$env:HSA_SEMGREP_CONFIG = "C:\security\semgrep-rules"This plugin runs Semgrep Community Edition (CE). If you point HSA_SEMGREP_CONFIG at a local checkout or bundle of Semgrep rules, make sure that ruleset only contains languages/features your Semgrep CE installation can analyze.
A concrete example is Apex: Semgrep documents Apex as a Pro Engine language. A local rules tree that includes a top-level apex rules directory can therefore make a CE scan report analysis errors. The plugin intentionally treats those errors as incomplete coverage (UNRESOLVED) instead of incorrectly reporting a clean PASS.
If you are using the default HSA_SEMGREP_CONFIG=auto, you normally do not need this workaround. It is mainly for users who keep their own local rules checkout.
Do not delete or edit your original rules tree just to make it CE-compatible. Create a separate filtered copy and point HSA_SEMGREP_CONFIG at that copy.
The example below copies a local rules tree while excluding only the top-level apex directory:
$source = "C:\security\semgrep-rules"
$dest = "C:\security\semgrep-rules-ce"
if (Test-Path $dest) {
Remove-Item -Recurse -Force $dest
}
New-Item -ItemType Directory -Force $dest | Out-Null
robocopy $source $dest /E /XD "$source\apex"
if ($LASTEXITCODE -ge 8) {
throw "robocopy failed with exit code $LASTEXITCODE"
}
$env:HSA_SEMGREP_CONFIG = $destrobocopy exit codes below 8 can still mean a successful copy; 8 or higher indicates a failure.
source_dir="$HOME/security/semgrep-rules"
dest_dir="$HOME/security/semgrep-rules-ce"
rm -rf "$dest_dir"
mkdir -p "$dest_dir"
rsync -a --exclude='/apex/' "$source_dir/" "$dest_dir/"
export HSA_SEMGREP_CONFIG="$dest_dir"Then run the audit again. A compatible scan should report Semgrep as PASS or FAIL based on findings, rather than UNRESOLVED because of unsupported-rule analysis errors.
This workaround is intentionally narrow: exclude only rules you have confirmed are incompatible with the Semgrep CE engine you are running. Semgrep's current product documentation lists Apex among the languages provided by Pro Engine:
The plugin itself does not upload your source code, but the scanners have their own behavior:
- Gitleaks runs locally.
- OSV-Scanner may contact vulnerability/package services depending on its configuration.
- Semgrep's default
autoconfig may download rules and may use Semgrep metrics according to Semgrep's own settings. The plugin preservesSEMGREP_SEND_METRICS,SEMGREP_APP_TOKEN, andSEMGREP_URLif you have set them.
If you want Semgrep to use only local rules, point HSA_SEMGREP_CONFIG at a local rules file/directory and configure Semgrep's own network/metrics settings the way you want them.
- PASS — scanner ran successfully and found nothing.
- FAIL — scanner ran and reported one or more findings.
- NOT_APPLICABLE — there was nothing relevant for that scanner to inspect.
- UNRESOLVED — coverage could not be trusted (missing scanner, timeout, malformed output, incomplete scanner analysis, unexpected scanner error, etc.).
- BLOCKED — the workspace itself could not be validated.
Overall precedence is FAIL → UNRESOLVED → PASS. A FAIL result can still set coverage_incomplete: true when a scanner found real findings but also reported partial analysis errors.
- It does not install or update scanners for you.
- It does not auto-fix findings.
- It does not scan full Git history with Gitleaks.
- It does not do ZAP/DAST scanning. Active web scanning has a different safety/authorization model and should be an explicit feature if it is added later.
- It does not replace Hermes' own dependency/supply-chain security commands.
The tests do not need the scanners installed; scanner processes are mocked except for one small bounded-output subprocess regression test.
python -m unittest discover -s tests -v
python -m compileall -q .Pull requests are welcome. See CONTRIBUTING.md.
MIT. See LICENSE.