MCP, MCP server
Attestor
The memory layer for agent teams.
Compatibility: Not stated.
Grade B
Minor issues only, no Medium or High. Worth a quick look at the findings below before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
PERMISSION_DELETE_FILES NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST SECRETS_PATH_DOTENV SECRETS_ENV_READ OBFUSCATION_FILE_OVER_READ_CAP OBFUSCATION_FILE_CAP_REACHED
Why this grade
- PERMISSION_DELETE_FILES Low
Contains a call that can delete files.
attestor/init_wizard.py, line 171
shutil.rmtree(path) - NETWORK_NO_FIXED_HOST Low
Makes a network call whose host is not written as a fixed address.
attestor/client.py, line 54
with urllib.request.urlopen(req, timeout=self.timeout) as resp: - NETWORK_UNNAMED_HOST Low
Calls a fixed host that the description does not name.
attestor/client.py, line 54
with urllib.request.urlopen(req, timeout=self.timeout) as resp: - SECRETS_PATH_DOTENV Low
Mentions a .env file.
attestor/init_wizard.py, line 46
`$ENV_VAR` references** (resolved from the environment / `.env`). - SECRETS_ENV_READ Note
Reads an environment variable whose name contains KEY, SECRET, TOKEN, PASSWORD or CREDENTIAL.
attestor/api.py, line 73
api_key = os.environ.get("PINECONE_API_KEY") - OBFUSCATION_FILE_OVER_READ_CAP Note
A file was over the read cap and was not fully read.
poetry.lock, line 1
# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. - OBFUSCATION_FILE_CAP_REACHED Note
The 400 file cap was reached before every file was read.
poetry.lock, line 1
# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
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
Concern
can delete files.
PERMISSION_DELETE_FILES
attestor/init_wizard.py, line 171
shutil.rmtree(path)
attestor/cli/commands/quickstart.py, line 208
return subprocess.run(
attestor/cli/commands/quickstart.py, line 217
out = subprocess.run(
Show more
attestor/cli/commands/quickstart.py, line 256
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
attestor/cli/commands/teardown.py, line 63
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
attestor/cli/commands/teardown.py, line 81
shutil.rmtree(store)
attestor/longmemeval/reporter.py, line 225
sha = subprocess.check_output(
attestor/longmemeval/reporter.py, line 231
status = subprocess.check_output(
evals/runner.py, line 143
proc = subprocess.run(
scripts/attestor_uninstall.py, line 53
subprocess.run(cmd, check=False, cwd=cwd)
Install and update
Pass
No install-time script found, and dependencies are pinned or absent.
Network
Concern
can reach a host that is not written as a fixed address. can reach api.foo. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
attestor/client.py, line 54
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
attestor/client.py, line 64
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
attestor/cli/commands/quickstart.py, line 97
with contextlib.suppress(OSError), socket.create_connection((host, port), timeout=timeout):
Show more
attestor/cli/commands/quickstart.py, line 107
resp = requests.get("http://localhost:11434/api/tags", timeout=2)
attestor/hooks/post_tool_use.py, line 30
# command like `curl -H "Authorization: Bearer ey..." https://api.foo`
attestor/hooks/post_tool_use.py, line 123
# `curl -H "Authorization: Bearer ..."` would otherwise land
attestor/infra/local/bench_latency.py, line 84
with urllib.request.urlopen(req, timeout=timeout) as resp:
attestor/infra/local/bench_latency.py, line 91
with urllib.request.urlopen(req, timeout=timeout) as resp:
attestor/locomo/runner.py, line 126
with urllib.request.urlopen(LOCOMO_URL, timeout=30) as resp:
commands/demo-recording.md, line 20
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/ui/memories
Dockerfile.api, line 76
r=urllib.request.urlopen(f'http://localhost:{p}/health', timeout=3); \
attestor/infra/local/api.Dockerfile, line 61
r=urllib.request.urlopen('http://localhost:8080/health', timeout=3); \
Secrets
Concern
reads a credential or environment file.
SECRETS_ENV_READ SECRETS_PATH_DOTENV
attestor/api.py, line 73
api_key = os.environ.get("PINECONE_API_KEY")
attestor/api.py, line 117
"password": os.environ.get("POSTGRES_PASSWORD", ""),
attestor/init_wizard.py, line 46
`$ENV_VAR` references** (resolved from the environment / `.env`).
Show more
attestor/api.py, line 130
"password": os.environ.get("NEO4J_PASSWORD", ""),
attestor/api.py, line 356
public_key = os.environ.get("ATTESTOR_JWT_PUBLIC_KEY")
attestor/init_wizard.py, line 57
doc.add(tomlkit.comment("Secrets use $ENV_VAR references (resolved from the env / ~/.attestor/.env), never plaintext."))
attestor/cli/_common.py, line 89
"""Load environment variables from a .env file.
attestor/cli/_setup_helpers.py, line 32
"""A `.env`-sourcing bash-wrapper MCP entry.
attestor/cli/_setup_helpers.py, line 37
inline secrets; instead we source `~/.attestor/.env` (the same pattern the
attestor/cli/_setup_helpers.py, line 39
committed config. `set -a` is required so un-`export`ed `.env` lines reach
attestor/cli/_setup_helpers.py, line 50
'set -a; [ -f "$HOME/.attestor/.env" ] && . "$HOME/.attestor/.env"; '
attestor/cli/_setup_helpers.py, line 143
``set -a`` auto-exports everything sourced from ``~/.attestor/.env`` so the
attestor/config/loader.py, line 572
if not os.environ.get("VOYAGE_API_KEY"):
attestor/config/loader.py, line 588
if not os.environ.get("PINECONE_API_KEY"):
attestor/retrieval/reranker.py, line 162
api_key = os.environ.get("COHERE_API_KEY")
attestor/store/embeddings.py, line 143
api_key = api_key or os.environ.get("VOYAGE_API_KEY")
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Note
a file was over the read cap and was not fully read. the file cap was reached before every file was read.
OBFUSCATION_FILE_OVER_READ_CAP OBFUSCATION_FILE_CAP_REACHED
poetry.lock, line 1
# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
tests/test_durable_forget_activities.py, line 1
"""ForgetActivities - one activity per backend, lanes from ``compliance.forget_lanes``.
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 e6b5c18e1ab7. can delete files. can reach a host that is not written as a fixed address. can reach api.foo. The description does not name that host. reads a credential or environment file. a file was over the read cap and was not fully read. the file cap was reached before every file was read.
Date and source
Date checked:
github.com
Commit graded: e6b5c18e1ab7d76147166eaa293fd7ac6ec30874
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.