MCP, MCP server
HEIDES
HEIDES is a deterministic harness that gives AI coding agents what they do not have on their own: a persistent map of the code, warnings derived from that map, and a verdict before a patch lands.
Compatibility: Not stated.
Grade C
One Medium finding. Read the findings before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
Rescanned at commit 5bcd68ecc94e, unchanged since the check below.
SECRETS_PATH_CREDENTIAL
Why this grade
- SECRETS_PATH_CREDENTIAL Medium
Mentions a credential store path (~/.ssh, id_rsa, .npmrc, .aws/credentials, credentials.json, .netrc).
src/config.rs, line 112
// A private key file: `id_rsa`, `server.pem`, `.ssh/id_ed25519`. These have
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Note
requests shell access. The manifest names this permission.
PERMISSION_SHELL_DECLARED
src/harmony.rs, line 921
= input()\n+ import subprocess\n+ subprocess.run(cmd, shell=True)\n+ token = \"ghp_ab
src/harmony.rs, line 974
" subprocess.run(cmd, shell=True)",
src/practice.rs, line 179
/// These do not need a taint flow to be wrong. `subprocess.run(cmd, shell=True)`
Show more
src/taint.rs, line 584
// `subprocess.run(`, `.call(`, `.check_output(` and `.Popen(` all reach a
src/taint.rs, line 2022
/// parameter is not a source, so `def go(cmd): os.system(cmd)` is silent
src/taint.rs, line 2030
let src = "def go(cmd):\n os.system(cmd)\n";
src/taint.rs, line 2069
let src = "def run():\n name = input()\n os.system(name)\n";
CHANGELOG.md, line 558
* **`staged` ran no security guards at all.** A patch adding `subprocess.run(cmd, shell=True)`, `requests.get(url, verify=False)`, `eval(cmd)` and a hardcoded `ghp_` token reported
Install and update
Note
README documents an installer that pipes a download into a shell. The docs document an installer that pipes a download into a shell.
INSTALL_DOCUMENTED_INSTALLER
README.md, line 173
curl -fsSL https://raw.githubusercontent.com/AbduljabbarBXR/heides/main/scripts/install.sh | bash
README.md, line 180
HEIDES_VERSION=v0.16.0 curl -fsSL https://raw.githubusercontent.com/AbduljabbarBXR/heides/main/scripts/install.sh | bash
scripts/install.sh, line 4
# curl -fsSL https://raw.githubusercontent.com/AbduljabbarBXR/heides/main/scripts/install.sh | bash
Network
Concern
can reach a host that is not written as a fixed address. can reach api.example.com. The description does not name that host. can reach 169.254.169.254. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
npm/install.js, line 18
// and HEIDES_VERSION is honoured so the same pin works for the curl installer
npm/test.js, line 28
// The same variable the curl installer uses, so one pin works everywhere.
scripts/install.sh, line 55
curl -fsSL "$(url_for)" -o "$dest.tmp"
Show more
src/taint.rs, line 2048
let src = "def go():\n requests.get(url)\n";
src/taint.rs, line 2256
let src = "async function proxy(req, res) {\n const target = req.query.url;\n const r = await fetch(target);\n res.send(r);\n}\n";
src/taint.rs, line 2268
"app.get('/p', (req, res) => {\n fetch(req.query.url).then(r => r.text());\n});\n";
src/taint.rs, line 2280
let js = "function p(req) {\n const u = req.query.u;\n return axios.get(u);\n}\n";
src/taint.rs, line 2285
let py = "def proxy(request):\n target = request.args['u']\n return requests.get(target)\n";
README.md, line 110
const r = await fetch('https://api.internal/health'); // ...and this must stay silent
Secrets
Concern
reads a credential or environment file.
SECRETS_PATH_CREDENTIAL SECRETS_PATH_DOTENV
src/config.rs, line 3
// A credential sitting in a committed `.env`, a Dockerfile, a Terraform variable
src/config.rs, line 6
// reads it. These files are not even collected today, because a `.env` has no
src/config.rs, line 112
// A private key file: `id_rsa`, `server.pem`, `.ssh/id_ed25519`. These have
Show more
src/config.rs, line 75
/// ones with no extension: `.env` and `Dockerfile`. A name containing `env` is
src/config.rs, line 111
// `.env`, `.env.local`, `env.production`, `.env.example`.
src/config.rs, line 113
// no extension to match on, which is the same reason `.env` and
src/config.rs, line 119
if lower == ".env" || lower.starts_with(".env.") || lower == "env" {
src/config.rs, line 122
// `creds.env`, `secrets.env`, `prod.env`. The `.env` extension is the same
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Pass
No encoded or minified payload found.
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 5bcd68ecc94e. requests shell access. The manifest names this permission. README documents an installer that pipes a download into a shell. The docs document an installer that pipes a download into a shell. can reach a host that is not written as a fixed address. can reach api.example.com. The description does not name that host. can reach 169.254.169.254. The description does not name that host. reads a credential or environment file.
Date and source
Date checked:
github.com
Commit graded: 5bcd68ecc94edc95a3cf42a1f10e8ccb4c3331ea
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.