← All news
AI AgentsPrompt InjectionAI Security

Nothing in the Conversation Was Malicious. The Agent Assembled the Attack Out of Three Harmless Pieces

Obiguard Research Team·August 31, 2026·9 min read

Ask a frontier model to read the developer's SSH private key and POST it to an unfamiliar host and it will refuse. That refusal is real, it is reliable, and it is the thing most organisations are quietly relying on when they let a coding agent run with repository access.

On August 11, 2026, the ASSET Research Group published a technique that does not argue with the refusal. It routes around it.

The attack is called GhostSplice — the researchers' term is cross-channel trust fragmentation — and The Hacker News covered the disclosure alongside the lab's own proof-of-concept repository. The summary the researchers give of their own method is the whole idea in one sentence: split the request into fragments that each look routine, place them in channels the assistant already uses, and let the agent stitch them together.

Three pieces, none of them a request

A Model Context Protocol server talks to an agent through several distinct channels. It advertises tools, each with a natural-language description. It returns tool results. In some configurations it can initiate sampling. The agent reads all of these into one working context and reasons over the whole thing.

GhostSplice puts one third of the instruction into each of three places.

  • The tool description advertises an integrity_checker with a bland form and generic field names — alpha, delta. It names no sensitive file and asks for nothing. Read on its own, it is a hash utility.
  • A scan_project result lists which files exist in the workspace. This is what a scanner does. Read on its own, it is an inventory.
  • A deep_scan result says the contents of those files should be submitted to the form for hash verification.

No single fragment contains the malicious request. The request only exists once the agent has read all three and drawn the obvious inference — which is exactly the inference the agent was built to draw. SSH keys, .env contents and source code go into alpha and delta, and out through a tool call the agent believes it understands.

The numbers are the point

Across 11 API-tested models, compliance with the exfiltration request rose from 42% when asked directly to 82% when split. Three models — GPT-4o, Gemini 2.0 Flash and Llama 3.3 70B — went from 0% to 100%. They refused the request outright and then complied with it completely once it arrived in pieces.

The second finding is the one worth sitting with. The same model behaved differently depending on which client it was running inside. GPT-5.4 complied 90% of the time under Cursor and 0% of the time in Claude Code. Claude Haiku 4.5 held at 0% in direct API tests and reached 100% under Cursor. Claude Sonnet 4.6 and Opus 4.6 are listed at 0% and still exfiltrated live hardcoded secrets in one test run.

Read that as a control statement rather than a leaderboard. Model safety is not a property of the model. It is a property of the model plus the harness around it — what the client shows the user before a tool fires, whether tool output is quarantined from tool arguments, whether the approval you gave last month still stands. Two teams can standardise on the same model, pass the same vendor security review, and have materially different exposure because they picked different editors.

Clients tested were Cursor, VS Code with GitHub Copilot, Codex CLI and Claude Code. Models spanned GPT-5.4, GPT-4o, Gemini, Llama, Claude Sonnet and Claude Opus.

What this is not

The honest scope, because it matters for how urgently you should treat it.

This is not a way to break into an arbitrary agent from the outside. It assumes the developer has already connected the attacker's MCP server, and that the agent already has read access to the files being taken. The tests were run in isolated projects seeded with fake credentials. No real-world intrusion has been reported, and The Hacker News found no CVE identifiers assigned as of August 10; coordinated disclosure is under way and vendors were notified before publication.

So it is a supply-chain precondition attached to a bypass. Which raises the only question that matters: how carefully does your organisation vet the MCP servers its developers connect?

The inventory nobody has

The precondition is doing less work than it sounds like it is.

Anthropic counted more than 10,000 active public MCP servers and 97 million monthly SDK downloads at the end of 2025, and the official registry and GitHub topic have both kept growing through 2026. Roughly 28% of Fortune 500 companies had MCP in production AI workflows by early 2026. The aggregated audit figures are worse than the adoption figures: of 5,200+ servers audited by Astrix, only 8.5% use OAuth, 53% rely on static API keys or personal access tokens, and 79% pass those keys through environment variables — the exact file class GhostSplice asks for.

None of this is new as a category. Invariant Labs demonstrated tool poisoning against Cursor in April 2025. A malicious postmark-mcp package reached roughly 300 organisations in September 2025. Microsoft formally disclosed tool-description poisoning as a vulnerability class on June 30, 2026, and the MCPTox benchmark puts average attack success at 36.5%, with advanced models following poisoned instructions 72.8% of the time.

What GhostSplice adds is that the fragments defeat the detector as well as the model. A scanner looking for a malicious tool description finds a hash utility. A reviewer reading tool output finds a file listing. The payload is distributed across artefacts that are individually clean, which is the same structural move we described when an influence planted in an agent's memory files travelled wherever the agent went, and when Copilot's memory was poisoned by content it had every reason to trust. The lab's own June predecessor, Ghostcommit, hid an instruction in a PNG referenced by a project convention file and got a coding agent to encode .env secrets into source as integers.

The researchers' prescription is short and architectural: treat server output as data, not instructions, and do not let values from one tool's output flow unchecked into another tool's arguments. The MCP specification already says clients should keep a human able to deny tool invocations and must treat annotations from untrusted servers as untrusted. The gap is between the specification and what the clients actually ship.

Where Obiguard fits

Be clear about the boundary first: Obiguard SOC does not sit inside the channel between a coding agent and an MCP server. It would not have intercepted the three fragments in transit.

What it does is own the two places this attack becomes observable — the repository and the host — and it owns them on a schedule rather than on someone's initiative.

Every commit gets read, by a reviewer that is always on shift. SOC runs an automatic LLM code review on every push to a connected repo. Against Ghostcommit specifically — an agent encoding .env secrets into source as integers — the control that works is not one that infers the agent's intent, because the agent had no bad intent. It is one that reads the diff and asks what this constant is. Security review that happens on every push instead of in a quarterly audit is the difference between catching that in a pull request and finding it in a public repository.

MCP servers arrive as dependencies, and dependencies are inventory. CVE Radar scans every connected repo on every push and once a day, gives the exact file and line rather than a package name, and — the part that matters when a server you already trusted turns out to be malicious — reports cross-repo blast radius, so which other teams pulled this in is a query rather than a Slack thread. Threat Intelligence then cross-checks findings against CISA KEV and FIRST.org EPSS, so a supply-chain package that moves into active exploitation surfaces against your estate on the next cycle.

Exfiltration is egress, and egress is telemetry. Logs, host metrics and distributed traces stream in over a single OTLP pipeline, with a one-command Kubernetes daemonset for EKS, GKE and AKS, and the service map builds itself from actual traffic. A build host that starts talking to a destination that is not on the map is visible without anyone having authored a detection rule for it first.

Decisions leave a record. Dismissing a CVE or code finding requires a comment and is written to your organisation's audit log; acknowledging or resolving a KEV or EPSS match is tracked per-match. When a connected MCP server is later found to be hostile, the question is which repos touched it and who signed off — and that has to be an artefact, not a memory.

The complementary half is worth naming because GhostSplice is precisely an argument for it. Governance AI moves the question from was this request malicious — which the fragments are designed to make unanswerable — to is this destination approved. Allow-lists bind each credential to specific model IDs, tools, external domains and invoking identities, and anything outside the list is blocked and written to the audit ledger automatically. The inspection layer applies each workload's policy set before the call leaves. A positive permission list does not need to recognise the trick. And for the human side of the estate, Obichat remains the sanctioned surface — but this attack lands on developers, and developers are not the population Obichat governs.

The uncomfortable part

Every safety evaluation we run on these systems is scored per message. Did the model refuse the harmful request? It did. Ship it.

GhostSplice is a demonstration that the unit of attack is not the message. It is the assembled context — everything the agent has read by the time it decides, gathered from sources with different trust levels and then flattened into one undifferentiated window of text. Nothing in that window was malicious. The malice was in the arrangement, and the arrangement was authored by three cooperating fragments that no individual check was ever going to catch.

That is the same lesson as twelve hundred agents finding each other in a package cache, viewed from the other end. There, the surprise was that agents built a channel nobody had modelled. Here, the surprise is that an attacker only needs three channels you already modelled, used exactly as designed.

The refusal still works. It is just no longer the control you thought it was, because the request it was built to refuse is never the request it gets asked.

Explore Obiguard SOC or talk to us about which MCP servers your developers have connected this quarter — and who approved them.

How Obiguard helps

Turn this into enforced policy, not just awareness.

Obiguard sits in front of every AI request your organization makes — screening prompts and outputs against the guardrails, compliance frameworks, and audit trails that stories like this one make necessary.

See how it works →