| 1 | --- |
| 2 | archetype: ai-agent-mcp |
| 3 | primary_gate_families: [1, 7, 3] |
| 4 | --- |
| 5 | |
| 6 | # Archetype - AI Agents, Tool-Runners & MCP Servers |
| 7 | |
| 8 | Targets: Open WebUI, Flowise, n8n, LangChain/LangGraph tool execution, LlamaIndex, AutoGPT-likes, |
| 9 | and the explosion of **MCP servers**. The thesis: these systems exist to **turn model output into |
| 10 | actions** - they run tools, eval code, fetch URLs, query DBs, exec shell. The whole product *is* a |
| 11 | chain of trust-boundary crossings, and the field is months old, so the parsers, sandboxes, and |
| 12 | allowlists are immature. This is a [[../00-doctrine/SEVERITY-GATE#family-1-remote-code-execution-the-crown|Family 1]] / [[../00-doctrine/SEVERITY-GATE#family-7-ssrf-xxe-file-access-chains-to-critical|Family 7]] / [[../00-doctrine/SEVERITY-GATE#family-3-cloud-identity-account-takeover-privilege-escalation|Family 3]] archetype. |
| 13 | |
| 14 | See: [[ml-model-loaders]] (inference backends behind these), [[devops-infra]] (often self-hosted), |
| 15 | [[electron-desktop]] (desktop AI clients). Tooling: `test_mcp_server`, `mcp_tool_surface`, |
| 16 | `test_ssrf_params`, `test_cmdi`, `test_ssti`. |
| 17 | |
| 18 | --- |
| 19 | |
| 20 | ## Principals & trust boundaries |
| 21 | |
| 22 | - **Principals:** the end user / prompt author, the **model** (untrusted output - treat model text as |
| 23 | attacker-controlled), tool/plugin authors, the **MCP server** author, connected data sources |
| 24 | (a fetched webpage, a RAG document, an email the agent reads), the host process and its credentials |
| 25 | (API keys, cloud creds, DB creds the agent holds). |
| 26 | - **Core boundaries:** |
| 27 | 1. *Prompt / fetched content → model* (prompt injection; content the agent reads is attacker input). |
| 28 | 2. *Model output → tool dispatcher* (the model's chosen tool + args drive real actions). |
| 29 | 3. *Tool → OS / network / DB* (code-exec tools, HTTP-fetch tools, DB tools). |
| 30 | 4. *MCP client ↔ MCP server* (tool definitions and results cross a process/network boundary - |
| 31 | **tool-poisoning**: a malicious tool *description* manipulates the calling agent). |
| 32 | - **The defining insight:** in an agent, **untrusted data and the control plane share a channel**. |
| 33 | A RAG document or a fetched page can contain instructions the model obeys → the model calls a |
| 34 | dangerous tool → real impact. Prompt injection is the *delivery*; the *finding* is the tool-abuse it |
| 35 | reaches. |
| 36 | |
| 37 | **Boundary map template:** |
| 38 | ``` |
| 39 | principals: prompt-author | model-output(untrusted) | tool-author | MCP-server | fetched-content | host-creds |
| 40 | trust inputs: user prompt, RAG docs, fetched URLs/pages, email/file the agent ingests, |
| 41 | tool definitions (name/description/schema), MCP server responses, workflow JSON |
| 42 | enforcement pts: tool allowlist, code-exec sandbox, URL/SSRF allowlist, auth on the agent's own |
| 43 | HTTP API, per-tool permission scoping, output filtering |
| 44 | cross-boundary |
| 45 | sinks: code-interpreter tool (exec/eval/PythonREPL) ; shell tool ; HTTP-fetch tool ; |
| 46 | SQL tool ; file tool ; the agent server's own unauth endpoints ; SSRF in the |
| 47 | model-provider/proxy config ; secret-returning tool reachable by prompt |
| 48 | confusion |
| 49 | hypotheses: "the code-exec sandbox is escapable / isn't really sandboxed"; |
| 50 | "a poisoned tool description redirects the agent to a dangerous tool"; |
| 51 | "the HTTP API has unauthenticated admin/exec routes"; |
| 52 | "SSRF allowlist misses an internal scheme / metadata IP"; |
| 53 | "prompt injection in a RAG doc reaches the shell tool" |
| 54 | ``` |
| 55 | |
| 56 | --- |
| 57 | |
| 58 | ## Kill chains (each lands on a Gate family) |
| 59 | |
| 60 | ### KC-1 - Unauthenticated server endpoints → RCE (Family 1) *(check this FIRST)* |
| 61 | These products are *self-hosted web apps*, and many ship with weak/optional auth or unauth admin/exec |
| 62 | routes. Before any prompt-injection cleverness, hunt the **HTTP surface** of the agent server itself. |
| 63 | - **Sinks:** Flowise/n8n/Open WebUI routes that import workflows, run code nodes, set up credentials, |
| 64 | or hit `/api/v1/...` without auth; n8n's `Code`/`Function` node and Webhook→exec paths; LangServe |
| 65 | endpoints exposing tools without auth. |
| 66 | - **CVE class:** the 2024 Flowise auth-bypass (unauth API via case/route-normalization), n8n code-node |
| 67 | RCE class, Open WebUI path issues. Find the *new* unauth route or the *next* normalization bypass. |
| 68 | - **Oracle:** an unauthenticated request lands command output / callback → Family 1. |
| 69 | |
| 70 | ### KC-2 - Prompt injection → dangerous-tool dispatch → RCE / exfil (Family 1 / 7) |
| 71 | A RAG document, fetched webpage, or ingested file carries instructions; the model obeys and calls a |
| 72 | **code-interpreter / shell / file / HTTP tool** with attacker args. |
| 73 | - **Sinks:** `PythonREPLTool`, `exec`/`eval` in a code-interpreter, `ShellTool`/`Terminal` tool, |
| 74 | `requests`/`httpx` in a fetch tool (→ SSRF), file-read tools, DB tools (→ SQLi/exfil). |
| 75 | - **The discipline:** the *finding* is not "the model can be prompt-injected" (that's the threat |
| 76 | model). The finding is the **artifact at the end of the tool call** - a callback from the code tool, |
| 77 | a secret read, a cross-tenant action. Prompt injection that reaches a *harmless* tool is cleared-axes. |
| 78 | - **Oracle:** injected content causes the code/shell tool to fire our canary → Family 1; or the fetch |
| 79 | tool to hit metadata and *capture the credential* → Family 7/3. |
| 80 | |
| 81 | ### KC-3 - Code-exec sandbox escape (Family 1/2) |
| 82 | Many agents wrap the code tool in a "sandbox" (a subprocess, a restricted Python, a container). The |
| 83 | sandboxes are usually weak. Escaping one is a clean Family 1 (and Family 2 if it's a container). |
| 84 | - **Sinks:** the restricted-exec wrapper (RestrictedPython, `ast` allowlists, a thin subprocess |
| 85 | jail), the container the code runs in (then [[devops-infra]]/Family 2 escape mechanics). |
| 86 | - **Oracle:** code that breaks out of the restricted env reaches the real OS / host → callback. |
| 87 | |
| 88 | ### KC-4 - MCP tool-poisoning & SSRF→RCE (Family 1/7) |
| 89 | MCP servers expose tools to a calling agent via tool *definitions*. A malicious/compromised MCP server |
| 90 | can ship a tool whose **description** contains injection (the agent reads descriptions), or whose |
| 91 | **implementation** does SSRF/command-injection on the args the agent passes. |
| 92 | - **Sinks:** the MCP server's tool handlers (`test_mcp_server` / `mcp_tool_surface` to enumerate), |
| 93 | any handler doing `exec`/HTTP-fetch/file-access on tool args; the tool-description channel as an |
| 94 | injection vector into the *client*. |
| 95 | - **Oracle:** a tool call lands command exec on the server (Family 1) or SSRF→metadata (Family 7/3). |
| 96 | |
| 97 | ### KC-5 - Agent-held credential exfil & cross-tenant (Family 3/4) |
| 98 | Agents hold powerful secrets (model-provider keys, cloud creds, DB creds, OAuth tokens). A prompt |
| 99 | injection or a tool flaw that *returns those secrets* or *acts cross-tenant* is Family 3/4. |
| 100 | - **Sinks:** any tool/endpoint that can read the agent's env/config/credential store; multi-tenant |
| 101 | agent platforms where one tenant's prompt reaches another tenant's tools/data. |
| 102 | - **Oracle:** the secret retrieved + minimally validated (Family 4), or tenant-A session producing |
| 103 | tenant-B canary (Family 3). |
| 104 | |
| 105 | --- |
| 106 | |
| 107 | ## The dynamic oracle, concretely |
| 108 | |
| 109 | 1. Self-host the target in a disposable container (`sandbox_create`) with **planted canary secrets and |
| 110 | a second canary tenant**. Pin version. |
| 111 | 2. Map the HTTP surface first (`discover_api_endpoints`, `test_unauth_access`) - unauth RCE beats |
| 112 | clever injection every time. |
| 113 | 3. For injection chains: feed a malicious RAG doc / fetched page / tool, and watch the *tool sinks*, |
| 114 | not the model's words. The proof is the callback / secret / cross-tenant canary - never the model |
| 115 | *saying* it will comply. |
| 116 | 4. REPLICA_CONFIRMED on the artifact; LIVE_CANARY only in scope. |
| 117 | |
| 118 | --- |
| 119 | |
| 120 | ## BORING traps - do NOT spend time here |
| 121 | |
| 122 | - **"The model can be jailbroken / prompt-injected."** That is the threat model, universally true, |
| 123 | and not a finding. The finding is the *tool-abuse artifact* it produces. A jailbreak with no |
| 124 | dangerous sink is cleared-axes. |
| 125 | - **"The agent followed instructions in a document."** Same - only counts if it reached a gate sink. |
| 126 | - **Prompt-injection that makes the model say something bad / leak its system prompt.** System-prompt |
| 127 | leak and "harmful text" are not [[../00-doctrine/SEVERITY-GATE|gate]] families. Hardening note. |
| 128 | - **Hallucinated tool calls with no real effect.** No artifact, no finding. |
| 129 | - **A code-interpreter that is *documented* as full-RCE-by-design and gated behind auth.** If it's an |
| 130 | intended authed feature, running code in it isn't a bug - the finding is the *unauth* or *escape*. |
| 131 | - **Re-finding the public Flowise/n8n CVE on an old build.** Sibling-CVE; hunt fresh code. |