The review before you install anything

Lesson 4 of 5 in Supply Chain and MCP Security: Code You Run, Content You Trust.

A review that produces a feeling is not a review. This one produces written answers to seven questions, each of which contains a specific attack from lesson two — so when someone asks why the checklist has an item, the answer is a threat, not a policy document.

Two habits make it fast enough to actually happen. Do it once per server, not once per developer. And answer from artefacts — the real tools/list output, the actual package version, the token’s real scopes — never from the README.

1 · Who publishes it — and can they prove it?

Prefer a first-party server from the vendor whose system you are integrating. Otherwise: is the namespace verified, does the repository have a history and identifiable maintainers, and does the package name resemble a more popular one? postmark-mcp impersonated a legitimate project’s GitHub identity, so “looks official” is exactly the signal an attacker forges.

Contains: malicious server, typosquatting. Does not contain: rug pulls — the same verified publisher ships version 1.0.16.

2 · What exactly will execute — version, artefact, update path?

Record the exact version or image digest, the package registry it comes from, and who reviews upgrades. A floating latest in a launch command means the next process start runs code nobody reviewed, with your credentials. If the server is load-bearing, vendor it: fork or mirror it and run from a commit you reviewed, so the update path is a pull request in your repo.

Contains: rug pulls, and it is the single highest-value item on this list because it converts a trust decision into a reviewable diff.

3 · What permissions does it want — and what is the smallest thing that works?

A stdio server takes credentials from its environment, so “install” usually means “paste a token.” Ask three questions before pasting: can this be read-only, can it be scoped to one project or repository instead of the org, and can it be a dedicated service identity rather than a human’s personal access token? For remote servers, confirm the token is audience-bound to that server — MCP clients MUST implement Resource Indicators (RFC 8707) and servers MUST validate that a token was issued for them, which is the protocol-level anti-passthrough control.

Contains: malicious-server blast radius, confused-deputy chains, token passthrough. This is the only control that still works after every other one has failed.

4 · Read the tool descriptions — they are prompts

Call tools/list and read the whole thing: names, descriptions, per-parameter descriptions, enum values, output schema docs, annotations. You are reading for text addressed to the model rather than describing the tool — priority claims, instructions to include extra data in arguments, claims about other servers’ tools, and anything that reads like policy. Count the write-capable and destructive tools while you are there, and note surprises: a docs server with an HTTP-fetch tool, a “read-only” server with an admin endpoint.

Then save a hash of each description so the next version produces a diff. And remember the spec’s own rule: clients MUST consider tool annotations untrusted unless they come from a trusted server. An annotation claiming a tool is read-only is a hint for display and policy input, never an enforceable guarantee — check the current schema for the exact hint fields, and enforce read-only-ness with the credential you issued instead.

Contains: tool-description poisoning, tool shadowing, surprise tool surface.

5 · Sandbox the server process itself

The server is untrusted code, so run it like untrusted code rather than like part of your host. In practice: a container or VM with a read-only root and an explicitly mounted working directory, a dedicated low-privilege user, no ambient cloud credentials reachable from inside (block the instance metadata endpoint), CPU/memory/file-descriptor limits, and no host network namespace.

The two Filesystem reference-server CVEs are the argument for this being an OS boundary rather than an application check: a colliding path prefix and a symlink both escaped a directory allowlist implemented in code. Path allowlists are worth having, and they are not a boundary — the kernel is.

Contains: malicious server, and every path-traversal-shaped bug in an otherwise honest server.

6 · Network reach and egress

Where can this process talk? A server that reads your data and can also reach arbitrary internet hosts is the exfiltration half of the lethal trifecta wearing a helpful costume. Give it an egress allowlist of the domains its job requires and log denials — a denial log is one of the few high-signal detections you get for free.

For local HTTP servers, check both spec provisions: servers MUST validate the Origin header on every incoming connection, responding 403 to invalid origins, and SHOULD bind only to localhost (127.0.0.1) rather than 0.0.0.0. Without those, a web page you visit can reach your local server — the shape of the MCP Inspector disclosure.

Contains: data exfiltration by a malicious server, DNS-rebinding and drive-by attacks on local servers.

7 · How would you know, and how do you stop it?

Before install, answer: where do this server’s invocations appear in your traces, who or what reviews them, how do you revoke its credential, and how fast can you remove it from every host that has it? Set the drift alert now — poll tools/list and compare against your stored hashes, because under revision 2026-07-28 change notifications are opt-in and best-effort, so absence of a notification is not evidence of no change.

Then write down the kill switch procedure while you are calm. Fifty developers with fifty local installs means fifty revocation paths, which is the strongest argument for fronting a shared system with one governed remote server instead.

Contains: slow-burn compromise, rug pulls you would otherwise notice late, and the “we could not turn it off” incident.

Stack those answers and you get a defence in depth with a deliberate order. Read the pyramid from the apex down: the top tier is the decision that removes the most risk, and each tier below it assumes every tier above has already failed.

Containment layers for a server you did not write

  1. Composition limits — what the agent may hold in one session

    The strongest control, because it is the only one that survives a perfect attacker. Do not put untrusted content, private data, and an outbound channel in the same session — that is the lethal trifecta, and Meta’s Rule of Two says the same thing prescriptively: at most two of the three, and if a task needs all three it should not run autonomously. Splitting a workflow into two agents with different mounts costs a day of design and removes the class.

  2. Identity and scope — the credential the server actually gets

    Assume the code is hostile and ask what it can reach. A read-only, project-scoped, dedicated service identity turns a total compromise into a bounded one. For remote servers, audience-bound tokens (RFC 8707) stop a server from replaying your token to a different service.

  3. Process sandbox — run it like the untrusted code it is

    A container or VM, read-only root, one explicitly mounted directory, a dedicated user, resource limits, no reachable instance-metadata endpoint. The Filesystem reference-server CVEs are the case study: application-level path allowlists were bypassed by a prefix collision and a symlink, and only an OS boundary was unaffected.

  4. Network egress control — where the process may talk

    An allowlist of the hosts the server’s job requires, with denials logged. This is the control that turns a successful injection into a failed exfiltration, and its denial log is high-signal — legitimate servers rarely try unexpected domains.

  5. Action gates, traces, and revocation — the operational floor

    An approval gate on the boundary-crossing and irreversible subset, traces that record which tool result preceded which tool call, drift alerts on the tool list, and a rehearsed kill switch. This tier does not prevent the first bad action — it decides whether you find out in minutes or in a quarter.

Tool: Tool Permission Lab — Practise the scoping decisions from tiers two and three — pick credentials and sandbox settings for a set of real-looking servers and watch the blast radius change in the Permission Lab.

Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.