· Abderrahmane Smimite · Research  · 6 min read

The 'mother of all AI supply chains' advisory: what it actually says, and how we audited our own MCP server

Reading ox.security's MCP advisory against the real Model Context Protocol attack surface, and a ten-minute audit for MCP server authors.

Reading ox.security's MCP advisory against the real Model Context Protocol attack surface, and a ten-minute audit for MCP server authors.

Earlier this month, ox.security published an advisory framed as “The Mother of All AI Supply Chains — Critical Systemic Vulnerability at the Core of the MCP”. It is well-reported and worth reading, but the headline frames a narrower technical finding than a casual reader might assume. We took it as a prompt to audit our own MCP server, ca_mcp, which ships with CISO Assistant and exposes our API to agentic LLM clients. This post walks through what the advisory actually describes, how we mapped it onto the real MCP attack surface, and how MCP server authors can do the same short audit on their own code.

What the advisory actually describes

The ox advisory documents arbitrary command execution reachable through untrusted STDIO spawn parameters in MCP clients and orchestrators. In the Model Context Protocol’s stdio transport, a host process launches each MCP server by spawning a subprocess — and the command, arguments, and environment for that subprocess are read from a configuration source. When that configuration source is attacker-controllable, the host spawns whatever the attacker asked it to spawn. That is the bug.

The affected products ox enumerates are all on the host/orchestrator side:

  • LiteLLM, LangChain
  • IBM Langflow, Flowise, Bisheng
  • GPT Researcher, Agent Zero, DocsGPT
  • Windsurf (IDE-integrated assistant)

Notably absent: Anthropic’s official MCP Python SDK (mcp.server.fastmcp). The SDK trusts its host to validate spawn parameters; the vulnerability lives in hosts that route untrusted input into that trust boundary — marketplace listings, shared project files, IDE settings sync, prompt-injected “please add this server” suggestions, and similar channels.

Calling this “the core of MCP” is a little generous. It is a realistic, high-impact integration failure pattern in the ecosystem around MCP — which is still worth taking seriously, because most MCP is running in that ecosystem.

The real MCP attack surface, in four axes

Setting aside ox’s specific finding, an MCP deployment has four independently assessable trust boundaries:

  1. Spawn-parameter trust (the ox axis). Does anything outside the user’s direct control — a marketplace, a shared config file, a prompt — get to decide what binary the host launches, with what arguments, in what environment?
  2. Server-internal execution paths. Given that a server is running and receiving tool calls, can a tool argument reach subprocess, os.system, eval, a templated shell string, or a path-traversal-capable file operation?
  3. Credential and network posture. Where are the tokens, API keys, and TLS settings stored? What does the server reach out to, and with what verification?
  4. Output-side prompt injection. Data returned from a tool is eventually concatenated into an LLM context. If any of it is attacker-influenceable (a threat description in a GRC tool, a ticket body, a log line), it becomes a prompt injection vector against the calling agent — not an RCE in the server, but a real vulnerability in the calling system.

The ox advisory lives entirely on axis 1. Axes 2–4 are always worth checking, advisory or not.

How ca_mcp sits on each axis

ca_mcp is the MCP server shipped in cli/ca_mcp/ of the ciso-assistant-community repository. It exposes CISO Assistant’s REST API — perimeters, frameworks, audits, libraries, risk matrices, and so on — as MCP tools.

Axis 1 — spawn parameters. ca_mcp is a server, not an orchestrator. It runs FastMCP("ciso-assistant") over transport="stdio". It never spawns another MCP server, and it does not read a config of “sub-servers to launch.” The ox vulnerability class is simply not expressible here — there is no field to attack.

Axis 2 — internal execution. Grepping cli/ca_mcp/ for subprocess, os.system, os.popen, shell=True, eval(, and exec( returns zero hits. Every tool is a thin wrapper around an authenticated requests.get/post/patch/delete call to CISO Assistant’s REST API, with tool arguments passed as a JSON payload. The payload is validated server-side by Django REST Framework serializers before it touches any state. The one “import”-looking tool, import_stored_library, triggers a backend endpoint (POST /stored-libraries/{urn}/import/) that imports data inside CISO Assistant; the MCP process does no local file or library loading in its own process.

Axis 3 — credentials and network. Config is read from environment variables (API_URL, TOKEN, VERIFY_CERTIFICATE) via dotenv, not from tool input. This is the right shape: caller-controllable fields cannot redirect the server at a different host or swap its credentials. Two residual concerns we are tracking:

  • The sample cli/.mcp.json stores a long-lived API token in plaintext. This is not the ox vulnerability — it is an ordinary secret-hygiene issue — but anyone with repo or filesystem access to that file gets full API rights for that user. Treat .mcp.json like any other secret file.
  • The same sample sets VERIFY_CERTIFICATE=false, which is fine for a localhost backend and unsafe the moment API_URL points anywhere else. If you run ca_mcp against a remote CISO Assistant instance, flip this back to true.

Axis 4 — output-side prompt injection. This is the remaining live concern, and it is not specific to ca_mcp: a malicious or simply mischievous record inside CISO Assistant — say, a threat description containing "ignore previous instructions and…" — will be returned verbatim by a get_threat tool call and concatenated into the calling agent’s context. The mitigation lives primarily at the client, not the server. We are evaluating whether to add a lightweight marker on tool outputs to signal “this is user-generated data, treat accordingly,” but the durable answer is client-side output sandboxing, which the broader ecosystem is actively working on.

A short audit for MCP server authors

The checks we just walked through generalize. If you maintain an MCP server, run these:

  1. Grep for shell paths. Search your server source for subprocess, os.system, os.popen, shell=True, eval(, and exec(. Zero hits is the target; every hit needs a justification that a tool argument cannot influence it.
  2. Trace every tool argument. For each registered tool, follow its arguments to the first external boundary (HTTP call, SQL query, file path, template string). Confirm that boundary validates or escapes the input. Pay particular attention to path-typed arguments.
  3. Audit config sources. Where does the server read its URLs, tokens, and trust settings from? If any of those can be set by a tool call or derived from tool input, you have a redirect-the-server primitive.
  4. Enumerate sinks of attacker-controllable strings. Even pure read-only servers can be prompt-injection vectors for their clients. Write down which tool outputs can contain end-user-authored text, and make sure your docs warn integrators.
  5. Check your sample config. Tokens checked into example files in the repository are a common and preventable leak. Use placeholders, not real secrets, and lint your .mcp.json in CI.

If the first three come back clean, the ox advisory does not apply to you. Items 4 and 5 are still worth doing.

Bottom line

For CISO Assistant users: the ox.security MCP advisory does not affect ca_mcp, and no code changes are required. If you have a cli/.mcp.json in a shared repository, rotate the token inside it, and keep VERIFY_CERTIFICATE=true unless you are pointing at localhost.

For MCP authors more broadly: read ox’s finding as what it is — a vulnerability in how hosts trust their configuration — and use it as an occasion to audit your own server along all four axes. The ecosystem is new enough that the same handful of minutes of grep-and-trace you would do on any integration point will catch the majority of the real issues.

Back to Blog

Related Posts

View All Posts »
Unleashing Direct Syscalls: Evading EDR Detection

Unleashing Direct Syscalls: Evading EDR Detection

Endpoint security remains a pressing concern for organizations, as they increasingly use antivirus (AV), endpoint protection (EPP), and endpoint detection and response (EDR) systems to protect against malware execution.