mcp@3.9.112
CAUTION· startup onlyPublisher claims: "Approval gate and audit trail for AI agent actions: policy check first, proof after. Any MCP client." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Startup only; authenticated tool behavior not tested.- Tested
- server startup over stdio (initialize sent) · every file read, file written and host contacted by what ran
- Not tested
- the tool list (the server exited before answering) · what the tools do when called with real credentials
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
GITHUB_TOKENMARROW_API_KEYMARROW_PASSIVE_TOKEN_USAGEConfiguration, not credentials: CLAUDE_CODE_CHILD_SESSION, CLAUDE_CODE_ENTRYPOINT, CLAUDE_PLUGIN_ROOT, CLAUDE_PROJECT_DIR, CODEX_HOME, GEMINI_CLI_SYSTEM_DEFAULTS_PATH, GEMINI_CLI_SYSTEM_SETTINGS_PATH, GET_A_KEY_LINE, GET_A_KEY_URL, GIT_CONFIG, GIT_CONFIG_COUNT, GIT_CONFIG_GLOBAL, GIT_CONFIG_PARAMETERS, GIT_CONFIG_SYSTEM, KEYLESS_KEY_ADVICE, MARROW_AGENT_CLIENT, MARROW_AGENT_ID, MARROW_AGENT_RUNTIME, MARROW_AUTO_ENROLL, MARROW_AUTO_HOOK, MARROW_BASE_URL, MARROW_CLIENT, MARROW_CONTEXT_HOOK_DEBUG, MARROW_EVENT_SPOOL_PATH, MARROW_FLEET_AGENT_ID, MARROW_HARNESS, MARROW_HOOK_BACKGROUND_NUDGE, MARROW_HOOK_DEBUG, MARROW_INTERNAL_NUDGE_LOCK, MARROW_KEY, MARROW_MODEL_USAGE_BILLING_MODE, MARROW_MODEL_USAGE_ENDPOINT, MARROW_MODEL_USAGE_PRICING_DIMENSIONS, MARROW_PASSIVE_BRIEF, MARROW_PING_TIMEOUT_MS, MARROW_REQUEST_TIMEOUT_MS, MARROW_SEATBELT_STRICT- Where it talks to
- getmarrow.ai (its own)Also claude.com — 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
- the tool list (the server exited before answering) · what the tools do when called with real credentials
Connect it with a scoped credential, under the guard, and read the third-party hosts first. The code names claude.com as well as its own vendor. The guard injects GITHUB_TOKEN, MARROW_API_KEY, MARROW_PASSIVE_TOKEN_USAGE only into requests to getmarrow.ai (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; startup only; authenticated tool behavior not tested) on 2026-11-08 and scored it 70/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; Destructive file system command detected. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 22 s · 2 scenarios · 0 deviationsStatic findings
const ONE_NAME_READ = /\bprocess\.env\.(?!(?:items|keys|copy)\b)([A-Za-z_]\w*)/g;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* `xargs` string is one word to it). A command that can spell one holds a word of the secret-path table (src/secret-paths.ts: `.env`, `.npmrc`, `.ssh`, ...)Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* `-` for the `_`, NFKC/NFKD-foldable forms, zero-width / format / combining characters, percent or Basic-auth base64Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.* holds `@`, `#` or `?` may also hold the real host (`https://deploy:443#@api.example.test` goes to hostFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…ess\.platform==="win32"\?"npx\.cmd":"npx",a\]\)\(require\("node:fs"\),\(process\.env\.HOME\|\|""\)\+"\/\.marrow\/runtime\/mcp\/(\d+\.\d+\.\d+)\/run",(\["-y","--pack…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// reason the mapper only gives a word that is no path (the pattern of `grep .env README.md`) in a command the policy reads whole (policyReadsAllWords).Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.files.push(path.join(dir, '.env'));Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// Same trusted resolution the installed hooks use: project .env files and non-private owner files cannot supply the key.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.files.push(path.join(dir, '.env.local'));Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// Paths in notices can be attacker-named: control, line-separator and formatFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.const configEnv = { ...env };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.S4: 'reading, copying or writing secrets (like .env files or private keys)',Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// Q3: only these .env templates are excepted. Never widen this to other .env files.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* False for a command that cannot read a secret FILE inside code the keyed policy does not parse (a quoted `bash -c`, `eval`, `sudo sh -c`, `ssh host` orFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.… that expectation is left as it is. */ const SECRET_FILE_WORDS = /(?<!process)\.env(?![a-z0-9_])|\.(?:ssh|aws|azure|kube|docker|gnupg|config|claude|marrow)|npmrc|n…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.`${h}/.kube/config`, `${h}/.docker/config.json`, `${h}/.npmrc`, `${h}/.pypirc`, `${h}/.netrc`, `${h}/.git-credentials`,Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* above stay unconditional. `<name>.env.example` never matches.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// (a glob or "$X/.env" is a stop when it can expand to one of these).Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* environment or the owner files in a trusted home (never repo .env files);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.'**/.kube/config', '**/.docker/config.json', '**/.npmrc', '**/.pypirc', '**/.netrc', '**/.git-credentials',Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const GET_A_KEY_LINE = `Get a key: ${GET_A_KEY_URL}. Day-one steps and commands: npx @getmarrow/mcp --help`;Fix: Pin versions and sources; vendor anything fetched at install time.* env or the same command) is added to ~/.kube/config, never substituted forFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* env or the same command) is added to ~/.kube/config, never substituted forFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.'**/.env', '**/.env.*', '**/.dev.vars',Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const passwdText = readSystemFile(fs, '/etc/passwd');Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* environment or the owner files in a trusted home (never repo .env files);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* A `<name>.env` file is read as `.env` is (same operations, same S-code) when it is there toFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.export declare const CONTROL_STATUS_COMMAND = "npx @getmarrow/install control status";Fix: Pin versions and sources; vendor anything fetched at install time.* npx @getmarrow/mcp --helpFix: Pin versions and sources; vendor anything fetched at install time.* such as `process.env` in `grep -rn "process.env" src`, is not a secret path; `.env` and `.env.*`Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…nst PLUGIN_KEY_STEPS = 'Marrow plugin: put MARROW_API_KEY in ~/.marrow/env, run chmod 600 ~/.marrow/env, then /reload-plugins. The seatbelt hooks keep working without…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.const ACTIVATE_COMMAND = 'npx -y @getmarrow/install@latest activate';Fix: Pin versions and sources; vendor anything fetched at install time.* npx @getmarrow/mcp (reads MARROW_API_KEY from env or an owner-only ~/.marrow/env)Fix: Pin versions and sources; vendor anything fetched at install time.`${h}/.env`, '/root/.ssh/id_rsa', '/root/.aws/credentials', `${h}/.marrow/seatbelt/salt`,Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* npx @getmarrow/mcp --helpFix: Pin versions and sources; vendor anything fetched at install time.* A `<name>.env` file is read as `.env` is (same operations, same S-code) when it is there toFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* npx @getmarrow/mcp (reads MARROW_API_KEY from env or an owner-only ~/.marrow/env)Fix: Pin versions and sources; vendor anything fetched at install time.4. Verify: npx -y @getmarrow/install@latest doctor --self-testFix: Pin versions and sources; vendor anything fetched at install time.? 'Run npx @getmarrow/install control disable --yes to disable local enforcement.'Fix: Pin versions and sources; vendor anything fetched at install time.// Shell operand for a chmod command built from the REAL path. Returns null whenFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.const REPO_KEY_FIX = 'run npx @getmarrow/install doctor, or move the line to ~/.marrow/env, then chmod 600 ~/.marrow/env';Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.// refused, so a symlinked file or folder gets no chmod operand on that path.Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.const REPO_KEY_FIX = 'run npx @getmarrow/install doctor, or move the line to ~/.marrow/env, then chmod 600 ~/.marrow/env';Fix: Pin versions and sources; vendor anything fetched at install time.exports.CONTROL_STATUS_COMMAND = 'npx @getmarrow/install control status';Fix: Pin versions and sources; vendor anything fetched at install time.return `${lead} Fix: replace the symlink with the real file (owner-only, mode 600); do not run chmod on the link.`;Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.: 'Run npx @getmarrow/install control enable to resume local enforcement; hook processes poll this state without reinstalling.',Fix: Pin versions and sources; vendor anything fetched at install time.…storage or place it in ~/.marrow/env with owner-only permissions before running npx -y --package=@getmarrow/mcp@latest marrow-mcp setup.' + (ignored ? `\n…Fix: Pin versions and sources; vendor anything fetched at install time.// chmod follows a symlink and would change its target while the link staysFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.* Both hooks are installed by `npx @getmarrow/mcp setup`. Either can beFix: Pin versions and sources; vendor anything fetched at install time.* Both hooks are installed by `npx @getmarrow/mcp setup`. Either can beFix: Pin versions and sources; vendor anything fetched at install time.const match = /^(?:npx @getmarrow\/install@(\S+) --repair|npx @getmarrow\/mcp@(\S+) setup|npx -y --package=@getmarrow\/mcp@(\S+) marrow-mcp setup|npm install @getmarrow\/sdk@(\S+))$/.exec(command);Fix: Pin versions and sources; vendor anything fetched at install time.* (`npx @getmarrow/install ...`, `marrow-install ...`, `node .../@getmarrow/install/bin/marrow-install.js ...`) with a `control` word otherFix: Pin versions and sources; vendor anything fetched at install time.…exact_next_action: 'Inspect and replace unsafe ~/.marrow/control.json, then run npx @getmarrow/install control status; protected actions remain blocked.' }; } } //# sourceMapping…Fix: Pin versions and sources; vendor anything fetched at install time.super('Local Marrow control state is unsafe or invalid. Protected actions remain blocked; inspect ~/.marrow/control.json and run npx @getmarrow/install control status.');Fix: Pin versions and sources; vendor anything fetched at install time.* (`npx @getmarrow/install ...`, `marrow-install ...`, `node .../@getmarrow/install/bin/marrow-install.js ...`) with a `control` word otherFix: Pin versions and sources; vendor anything fetched at install time.exactFix: `Marrow key was found in ${printablePath(filePath)}. Keep this file private and run npx @getmarrow/install doctor to verify.`,Fix: Pin versions and sources; vendor anything fetched at install time.* Codex's kill clock starts when it spawns the hook command, so the time npxFix: Pin versions and sources; vendor anything fetched at install time.…\\d+\\.\\d+\\.\\d+)/run"; if \\[ -x "\\$M" \\]; then "\\$M" ${LOCAL_ARGS}; else npx -y --package=@getmarrow/mcp@\\2 marrow-mcp \\3; fi; \\}`, 'g'); const LOCAL_SPAWN_…Fix: Pin versions and sources; vendor anything fetched at install time.…ow.ai/docs#start-here (Claude Code plugin: put MARROW_API_KEY in ~/.marrow/env, chmod 600, then /reload-plugins). Agent: do not retry this action.'; /** Seatbelt mode…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.const PLUGIN_KEY_HINT = ' (Claude Code plugin: put MARROW_API_KEY in ~/.marrow/env, chmod 600, then /reload-plugins)';Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.* Codex's kill clock starts when it spawns the hook command, so the time npxFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…dit Marrow settings; tell the user it was stopped. If this keeps happening, run npx -y @getmarrow/install@latest doctor. Code: U5.fail_closed/hook_error.'; /** * Sea…Fix: Pin versions and sources; vendor anything fetched at install time.const INSTALLER_REPAIR = 'The owner can repair it by running npx -y @getmarrow/install@latest --repair --cwd <project folder> from a terminal outside the project.';Fix: Pin versions and sources; vendor anything fetched at install time.const hookCommand = (entrypoint) => `npx -y --package=${exports.MCP_PACKAGE_SPEC} marrow-mcp ${entrypoint}`;Fix: Pin versions and sources; vendor anything fetched at install time.…this machine\'s setup. Fix (for the person at this machine, not the agent): run npx -y @getmarrow/install@latest doctor, or add a Marrow key (getmarrow.ai/docs#start-…Fix: Pin versions and sources; vendor anything fetched at install time.* The npx form of an installer local-runtime hook command, or the commandFix: Pin versions and sources; vendor anything fetched at install time.const DOCTOR_FIX = 'Run `npx -y @getmarrow/install@latest doctor` in this terminal to check this machine\'s Marrow setup, then retry.';Fix: Pin versions and sources; vendor anything fetched at install time.* The npx form of an installer local-runtime hook command, or the commandFix: Pin versions and sources; vendor anything fetched at install time.* hook process and set from each host's real kill timeout asFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.exports.CLAIMED_NO_KEY_TEXT = 'Marrow is linked to an account but has no working key; owner: run `npx -y @getmarrow/install@latest doctor`.';Fix: Pin versions and sources; vendor anything fetched at install time.return 'Marrow doesn\'t know this agent yet. Run `npx @getmarrow/install` again in this terminal, then retry.';Fix: Pin versions and sources; vendor anything fetched at install time.* Gemini CLI 5 s. The margin covers npx start-up before the process starts.Fix: Pin versions and sources; vendor anything fetched at install time.…d+\\.\\d+)/run"; if \\[ -x "\\$M" \\]; then exec "\\$M" ${LOCAL_ARGS}; fi; exec npx -y --package=@getmarrow/mcp@\\2 marrow-mcp \\3'$`); const LOCAL_INNER_RE = new Reg…Fix: Pin versions and sources; vendor anything fetched at install time.…ow.ai/docs#start-here (Claude Code plugin: put MARROW_API_KEY in ~/.marrow/env, chmod 600, then /reload-plugins).'; /** The label of a stop. A script Marrow could not…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.…nd host hook review. The governed wrapper remains an explicit bounded fallback: npx @getmarrow/install run --agent <agent-id> -- -- <command>.', capability.exact_next_action,…Fix: Pin versions and sources; vendor anything fetched at install time.// Codex: 5 s kill, then it runs the call. npx start-up before this processFix: Pin versions and sources; vendor anything fetched at install time.* T2 (control-file gap): a write, delete, move or chmod of Marrow's own control files, of the hooks settings of any host, or of theFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.* `sh -c` wrapper), in milliseconds, so a host's kill clock that started atFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…ial from trusted secret storage and its exact original agent identity, then run npx -y --package=@getmarrow/mcp@latest marrow-mcp drain-spool. Never put the credentia…Fix: Pin versions and sources; vendor anything fetched at install time.…or line break first. return text.replace(/[\u2028\u2029]/g, '\n').replace(/[\u000b\u000c\u00a0\u0085\u1680\u2000-\u200a\u202f\u205f\u3000]/g, ' ').replace(/[\u2013\u2014\u2015]/g, '-').replace…Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own.* Gemini CLI 5 s. The margin covers npx start-up before the process starts.Fix: Pin versions and sources; vendor anything fetched at install time.…recovery is exhausted; no local action is required. An explicit operator drain (npx -y --package=@getmarrow/mcp@latest marrow-mcp drain-spool) remains available but i…Fix: Pin versions and sources; vendor anything fetched at install time.* Codex's kill clock starts when it spawns the hook command, so the time npxFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.* hook process and set from each host's real kill timeout asFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.// npm rewrites its process title: /proc shows "npm exec …" (or "npx …") as one string.Fix: Pin versions and sources; vendor anything fetched at install time./** A process that only launches the hook: npx or npm (exec), or a `sh -c` wrapper. */Fix: Pin versions and sources; vendor anything fetched at install time.…e MCP tools on demand. For consequential CLI actions, use the governed wrapper: npx @getmarrow/install run --agent <agent-id> -- -- <command>. Custom hosts need a bounded event adapt…Fix: Pin versions and sources; vendor anything fetched at install time.export declare const CLAIMED_NO_KEY_TEXT = "Marrow is linked to an account but has no working key; owner: run `npx -y @getmarrow/install@latest doctor`.";Fix: Pin versions and sources; vendor anything fetched at install time.? 'The server rejected delivery authentication or authorization. Restore the credential and agent binding, then run npx -y --package=@getmarrow/mcp@latest marrow-mcp drain-spool.'Fix: Pin versions and sources; vendor anything fetched at install time.exports.CLAIMED_NO_KEY_TEXT = 'Marrow is linked to an account but has no working key; owner: run `npx -y @getmarrow/install@latest doctor`.';Fix: Pin versions and sources; vendor anything fetched at install time.* Codex's kill clock starts when it spawns the hook command, so the time npxFix: Pin versions and sources; vendor anything fetched at install time.…, so holds and approvals are NOT recorded. Put MARROW_API_KEY in ~/.marrow/env (chmod 600) or start the host with it, then restart the session.'; let armed = false; f…Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.* `sh -c` wrapper), in milliseconds, so a host's kill clock that started atFix: 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
No advisories in OSV for @getmarrow/mcp@3.9.112 as of 6d ago. This is the package itself, not its dependencies.
What would make this Verified
10 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Unclaimed publisher≈ +8 on the totalClaim getmarrow: 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.
- Destructive file system command detected≈ +4 on the totalBuild commands from fixed arguments; do not interpolate untrusted strings into a shell.
- 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.
- Privileged sudo command≈ +4 on the totalBuild commands from fixed arguments; do not interpolate untrusted strings into a shell.
- 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.