terse-mcp@0.49.3
CAUTION· not startedPublisher claims: "Lossless-first compression layer for AI-agent tool outputs — byte-faithful on fields you mark critical, configurable lossy reduction only where you opt in." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Not started: dependency install failed; the server itself was not observed.- Tested
- the dependency install step · every file read, file written and host contacted by what ran
- Not tested
- server startup · the tool list · tool behavior
What this means for the label: Caution here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
- no credential variables read in the code
- Where it talks to
- no vendor host named in the codeAlso openrouter.ai — not the publisher's domain; check what for before connecting.
- What the honeypot saw
- no credential files read · no network
- What we could not test
- server startup · the tool list · tool behavior
Connect it under the guard. Not started: dependency install failed; the server itself was not observed. The code names no credential variable; the guard pins the network to what the honeypot saw and logs every call.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (2 scenarios; not started: dependency install failed; the server itself was not observed) on 2026-11-15 and scored it 68/100 (Caution). It is not known to be malicious, but it has behaviour or code a security policy should decide on before install. Notable findings: URL to the cloud instance metadata address; URL with embedded credentials; URL with embedded credentials. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 1 s · 2 scenarios · 0 deviationsStatic findings
(plan F5). The previous `subprocess.run(cmd, timeout=...)` only everFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.place a kill mid-write could leave half-written. The file holds real MCP tool-callFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.proc = subprocess.Popen(cmd, cwd=cwd, env=env, stdout=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.* A downstream 302 to `http://169.254.169.254/…` was FOLLOWED, and its body wasFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…ssy_servers) is\nthe next slice.","verified_at":"2026-07-17T21:39:51Z"}},"url":"https://api.github.com/repos/inth3shadows/terse/commits/b5c40f860151c41fcc606ed645f387833002f7a3","html_url":"https://github.com/inth3shadows/terse/commit/b5c4…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.the moment the file is CREATED -- no write-then-chmod window where aFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts."""`url` with any userinfo and query string masked: `https://u:pw@h/mcp?token=x` is aFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…ure_io write/append restricted-permission helpers\n\nThe module closes a TOCTOU chmod race for files holding secrets (API keys\nin MCP env blocks) but had no dedicate…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.pass # already gone -- nothing to killFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run(["git", "worktree", "remove", "--force", str(workdir)],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.…e downstream \"reply,\" flowing straight into the model's context; an internal `http://169.254.169.254/…` URL is an SSRF primitive. terse *widened* the surface here vs. a compliant H…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…ed is now atomic (temp + fsync + os.replace), fixing the\n non-atomic ~/.claude.json / policy.json writes at the primitive; symlink refusal kept.\n- transport: refuse link-local/cloud-metadata SSRF targets (169.254.169.254,\n metadata.goog…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.# `--url=https://u:pw@h`, `DATABASE_URL=postgres://u:pw@db`: the value half isFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…adows/terse/git/blobs/7b94542b34e03852192ff7bf005e20ed0196b5be","download_url":"https://raw.githubusercontent.com/inth3shadows/terse/main/src/terse/__init__.py","type":"file","_links":{"self":"https://api.github.com/repos/inth3shadows/ters…Fix: Pin versions and sources; vendor anything fetched at install time.proc = subprocess.run(command, shell=True, cwd=workdir, capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run(["node", str(TOON_SCRIPT)], input=raw, capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run(["node", str(TOON_SCRIPT)], input=raw, capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.…ure_io write/append restricted-permission helpers\n\nThe module closes a TOCTOU chmod race for files holding secrets (API keys\nin MCP env blocks) but had no dedicate…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.# kill attempt, then take whatever communicate() gives us (emptyFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run(["git", "worktree", "add", "--detach", str(wt), pinned_commit],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(["git", "rev-parse", "--show-toplevel"], cwd=HERE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# SSRF primitive (`http://169.254.169.254/…`) whose response is fed straight into theFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…silently skipped)\n`_fold_records` key-order drift (value-lossless; a fix would kill the tabularization win), the stats-ledger rotation TOCTOU (self-heals, benign), …Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…tputs — selective per-tool, byte-faithful, no decode step.","fork":false,"url":"https://api.github.com/repos/inth3shadows/terse","forks_url":"https://api.github.com/repos/inth3shadows/terse/forks","keys_url":"https://api.github.com/repos/i…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…s now atomic** (temp + `fsync` + `os.replace`), fixing the non-atomic `~/.claude.json` / `policy.json` writes at the primitive — a crash mid-write can no longer truncate the user's live config. Symlink refusal preserved; no orphan temp/emp…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.only if even the post-kill `communicate()` couldn't reap the process (anFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…d20342a2116cdf8943bc0ce07de622b4c022a","msg":"install-mcp: support project (.mcp.json) and local (nested projects.<path>) scope (#59)\n\nExtends install-mcp/uninstall-mcp with --scope {user,project,local} (default\nuser, preserving current…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.self.proc = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# the group kill didn't finish reaping in time -- one more directFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…om","date":"2026-07-03T00:01:43Z"},"message":"install-mcp: support project (.mcp.json) and local (nested projects.<path>) scope (#59)\n\nExtends install-mcp/uninstall-mcp with --scope {user,project,local} (default\nuser, preserving current…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.(`start_new_session=True`, i.e. setsid) so a timeout can kill the WHOLEFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.self.proc = subprocess.Popen( # noqa: S603 — cmd is operator-supplied, by designFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run([launcher, "--version"], capture_output=True, timeout=10,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.want, got = (subprocess.run(["/bin/bash", "-c", text], cwd=tmp_path, env=env,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.survives on widening the tuple and is disclosed as equivalent, not a kill — the sameFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.proc = subprocess.run(["node", str(CMCP_SCRIPT)], input=raw, capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# project-scoped `.mcp.json` (see install_mcp.py), so this is not purely operator input.Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.proc = subprocess.run([rtk, "rewrite", job["cmd"]], capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run([rtk, "--version"], capture_output=True, env=env, cwd=home,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# is an optimization — a bug in it must not kill that peer's output stream.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run([sys.executable, str(script), sample_dir], check=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.umask between file creation and the chmod call. `os.fchmod` runs on the open descriptorFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.if wire is not None: # before the reaper, so `stop` survives a quick kill (#528)Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.proc = subprocess.run([rtk, "pipe", "-f", job["filter"]], input=job["text"],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(["unshare", "-rn", "--pid", "--fork", "--kill-child", "--", "true"],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.exception here would otherwise kill the proxy's reader thread."""Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.tagged = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# accumulating transport failures early is one to kill early.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(["git", "rev-parse", "--git-common-dir"],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# A bare `NAME=VALUE` arg (`docker run -e GH_TOKEN=...`, `npx ... API_KEY=...`) carries itsFix: Pin versions and sources; vendor anything fetched at install time.# a label every unrelated `python -m ...` / `npx ...` wrap in the fleet shares, so readingFix: Pin versions and sources; vendor anything fetched at install time.proc = subprocess.run(["node", str(HERE / "toon_encode_batch.mjs")], input=feed,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# to do so. The old 2s cap could kill the daemon thread mid-drain on a largeFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
Not checked against OSV yet; the weekly check has not reached this version.
What would make this Verified
12 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- URL to the cloud instance metadata address≈ +9 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Unclaimed publisher≈ +8 on the totalClaim inth3shadows: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- URL with embedded credentials≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Direct script execution from GitHub raw URL≈ +4 on the totalPin versions and sources; vendor anything fetched at install time.
- Python subprocess execution detected≈ +2 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- Process kill command≈ +2 on the totalBuild commands from fixed arguments; do not interpolate untrusted strings into a shell.