Other formats agents might prefer:
markdownjsonllms.txt

Agent? You probably want markdown or json, or Pod over MCP.

Reported issues for mcpm

Pod holds 15 of 15 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to mcpm.

Most discussed

[security][LOW] guard cleanup compares sanitized installed names vs raw pin keys (prune mismatch)

Severity: LOW

Location

src/guard/cli.ts:263,270-271 (cleanup)

Summary

cleanup builds the installed-server set by pushing names through sanitize() (strips control chars, truncates to 256), but compares them against raw pin keys when deciding which pins are orphans:

for (const s of c.servers) installedServerNames.add(sanitize(s.name)); // sanitized
...
for (const serverName of Object.keys(pins.servers))
  if (!installedServerNames.has(serverName)) orphanPinned.push(se

[Read the thread](https://github.com/getmcpm/cli/issues/28) · 2026-06-01 · closed · 1 comment

### [security][LOW] guard disable reconstructs original command from unauthenticated wrapped args

## Severity: LOW

## Location
`src/guard/wrap.ts:146-170` (`unwrapEntry`), `src/guard/orchestrator.ts:233,260`

## Summary
`mcpm guard disable` reconstructs the original server command by scanning the wrapped args for the `--server-name <name> --` marker and treating whatever follows as the original `command`/`args`. The marker is not authenticated, so a doctored wrapped entry (or a buggy manual edit) can steer `unwrapEntry` into writing an arbitrary `command` into the client config. Lower sever

[Read the thread](https://github.com/getmcpm/cli/issues/29) · 2026-06-01 · closed · 0 comments

### [security][LOW] guard pattern engine has no per-match regex timeout / leaf-length cap

## Severity: LOW

## Location
`src/guard/patterns.ts:119-160` (`normalizeForMatch`, `inspectAgainstSignatures`)

## Summary
The pattern engine matches attacker-controlled leaves up to `MAX_LEAF_BYTES` (1 MB) synchronously on the relay hot path, with no per-match wall-clock budget.

**Note:** the *currently shipped* signatures are **not** vulnerable to catastrophic backtracking — I benchmarked them (1k → 0.13 ms, 50k → 0.13 ms, 200k → 0.58 ms; linear), because the optional alternation groups are 

[Read the thread](https://github.com/getmcpm/cli/issues/27) · 2026-06-01 · closed · 0 comments

### [security][LOW] Config writes follow symlinks (.tmp/.bak/config) — add O_NOFOLLOW

## Severity: LOW

## Location
`src/config/adapters/base.ts:55-76` (`writeAtomic`)

## Summary
`writeAtomic` writes `${configPath}.tmp` and `${configPath}.bak` with plain `writeFile`, which follows existing symlinks. On a shared/multi-user machine (or via another MCP server with filesystem write access), an attacker can pre-create `<config>.bak` or `<config>.tmp` as a symlink to a sensitive file (e.g. a shell rc file) so mcpm's write lands on the symlink target. The final `rename` of `.tmp` is co

[Read the thread](https://github.com/getmcpm/cli/issues/26) · 2026-06-01 · closed · 0 comments

### [security][LOW] Config backup (.bak) stores re-serialized JSON and is overwritten on every write

## Severity: LOW

## Location
`src/config/adapters/base.ts:63-68`

## Summary
The `.bak` written before each config mutation is a re-serialized copy of the **parsed** object (`JSON.stringify(previousContent)`), not the original file bytes — so formatting, key order, and any JSONC/comments are lost. It is also overwritten on **every** write, so after two mcpm operations the user's original pre-mcpm config state is gone.

## Recommended fix
Copy the raw original file bytes, and write the backup on

[Read the thread](https://github.com/getmcpm/cli/issues/25) · 2026-06-01 · closed · 0 comments

### [security][MEDIUM] Trust gate blind to medium severities; normaliseSeverity fails open; minTrustScore:0 overridable

## Severity: MEDIUM

## Location
`src/commands/publish/check.ts:49-55` (`assertTrustGate`), `src/scanner/trust-score.ts:133-159`, `src/scanner/tier2.ts:97` (`normaliseSeverity`), `src/server/tools.ts:124` + `src/server/handlers.ts:129-150`

## Summary
Three related gaps let low-quality/abusive servers slip through:

1. **Medium blind spot.** The publish gate and the score's cap-to-0 rule key only on `critical`/`high`. Every `detectExfilArgs` finding is `medium` (e.g. exfil-shaped args `url`/`end

[Read the thread](https://github.com/getmcpm/cli/issues/24) · 2026-06-01 · closed · 0 comments

### [security][MEDIUM] Config adapters: prototype-pollution gap on server names; import runs no trust scan

## Severity: MEDIUM

## Location
`src/config/adapters/base.ts` (read/addServer/removeServer/setServerDisabled), `src/commands/import.ts`

## Summary
Server names read from untrusted IDE configs and via `mcpm import` are never validated against `__proto__` / `constructor` / `prototype`, and the server maps are plain objects rather than null-prototype. Object-literal assignment (`{ [name]: ... }`) does not pollute `Object.prototype` directly, but index reads/destructures keyed on `__proto__` (`exi

[Read the thread](https://github.com/getmcpm/cli/issues/23) · 2026-06-01 · closed · 0 comments

### [security][MEDIUM] mcpm_up MCP tool: documented guards are dead code; auto-confirms install/removal if revived

## Severity: MEDIUM

## Location
`src/server/index.ts` (registration absent), `src/server/handlers.ts:375-441` (`handleMcpUp`), `src/server/tools.ts:101-150` (`UpInput`, TOOL_DEFINITIONS entry)

## Summary
`CLAUDE.md` V1.3 claims `[x] mcpm_up MCP server tool (destructiveHint: true)` and `[x] Path traversal protection on mcpm_up MCP tool input`. Both are effectively false at runtime:

- The tool is **never registered** in `src/server/index.ts` (only 8 tools are wired; registration ends at `mcpm_s

[Read the thread](https://github.com/getmcpm/cli/issues/22) · 2026-06-01 · closed · 0 comments

## Most recent

### [security][MEDIUM] Registry client follows redirects (SSRF) and reads unbounded response bodies

## Severity: MEDIUM

## Location
`src/registry/client.ts:145-173` (`get`), `src/registry/publish-client.ts:23-45`, `src/registry/pagination.ts`

## Summary
Two issues in the shared HTTP path:

1. **SSRF / redirect following.** `baseUrl` is fully overridable and `fetch` is called without `redirect: "manual"`, so the default redirect-follow behavior lets a registry response (or an attacker-controlled `baseUrl`) 30x-redirect the client to internal hosts (`http://169.254.169.254/...`, `http://localh

[Read the thread](https://github.com/getmcpm/cli/issues/21) · 2026-06-01 · closed · 0 comments

### [security][MEDIUM] guard relay forwards full process.env to wrapped server; buildSafeEnv is dead code

## Severity: MEDIUM

## Location
`src/guard/run-inner.ts:160-176`, `src/guard/relay.ts:79-85,131`

## Summary
`startRelay` defaults its child env to `buildSafeEnv()` — an allowlist designed (per its own doc comment) to avoid "leaking unrelated parent secrets (`OPENAI_API_KEY`, `AWS_*`, `GITHUB_TOKEN`) to a server we are wrapping precisely because we don't fully trust it." But the production caller always supplies `env`:

```ts
// run-inner.ts
childEnv = await resolveEnvPlaceholders(process.env);

[Read the thread](https://github.com/getmcpm/cli/issues/20) · 2026-06-01 · closed · 0 comments

### [security][MEDIUM] Integrity sidecars are unkeyed SHA-256 — no protection vs same-user/postinstall tampering

## Severity: MEDIUM

## Location
`src/guard/pins.ts` (`fileSha`, `*.integrity` read/write), `src/guard/policy.ts` (same pattern for `guard-policy.yaml.integrity`)

## Summary
The `.integrity` sidecars are a plain `sha256:<hex>` of the file, stored next to the file with the same (writable) permissions. There is **no key**, so any process that can modify `pins.json` / `guard-policy.yaml` can recompute and rewrite the sidecar to match. There is no asymmetry between the attacker and the legitimate w

[Read the thread](https://github.com/getmcpm/cli/issues/19) · 2026-06-01 · closed · 0 comments

### [security][HIGH] health-check leaks env secrets to untrusted server (denylist instead of allowlist)

## Severity: HIGH

## Location
`src/scanner/health-check.ts:27-95` (`buildHealthCheckEnv`), spawn at `:188`

## Summary
The post-install health check spawns the **freshly-installed, untrusted** MCP server and passes it an environment built by copying **all** of `process.env` and subtracting a hardcoded denylist (`SENSITIVE_ENV_NAMES` / `SENSITIVE_ENV_PREFIXES`). CLAUDE.md's 2026-05-17 decision states env should be **allowlisted, not process.env passthrough**; this is the inverse, and the denylis

[Read the thread](https://github.com/getmcpm/cli/issues/18) · 2026-06-01 · closed · 0 comments

### [security][HIGH] mcpm publish sends GitHub token to arbitrary --registry host (token exfiltration)

## Severity: HIGH

## Location
`src/registry/publish-client.ts:20-31`, `src/commands/publish/submit.ts:39`

```ts
const url = `${registryUrl}/v0.1/servers`;
headers: { Authorization: `Bearer ${token}` }   // token = GITHUB_TOKEN / MCPM_TOKEN

Summary

mcpm publish --registry <url> flows unvalidated into the Authorization: Bearer header. There is no scheme check, no host allowlist, and the default fetch follows redirects. The token source is correctly env-only (never a CLI flag), but

Read the thread · 2026-06-01 · closed · 0 comments

[security][HIGH] guard detection bypass: signatures don't scan structuredContent, error, or inputSchema

Severity: HIGH

Location

src/guard/patterns.ts:56-94 (targetSubtree), src/guard/signatures.ts

Summary

The pattern engine narrows each signature target to a single JSON path, leaving standard MCP fields completely unscanned. A malicious server evades the headline OWASP signatures by relocating its payload:

  • tool_response walks only result.content (patterns.ts:60). Injection placed in result.structuredContent (a standard MCP result field) or in a JSON-RPC error obje

Read the thread · 2026-06-01 · closed · 0 comments

[security][HIGH] Encrypted secret store uses a non-secret encryption key (hostname + username)

Severity: HIGH

Location

src/store/keychain.ts:26-28

const MACHINE_PASSPHRASE = new TextEncoder().encode(
  `mcpm:${os.hostname()}:${os.userInfo().username}`
);

Summary

The AES-GCM key protecting ~/.mcpm/secrets.enc.json is derived (PBKDF2, 600k iterations, per-value salt) from hostname + username only. Neither value is secret — both are trivially recoverable by anyone who obtains the encrypted file (process listings, file paths, shell history, backups, cloud sync, o

Read the thread · 2026-06-01 · closed · 0 comments

The remaining reports are on the project's issue tracker.