Microsoft Research: Hijacking AI Agents via Malicious MCP Descriptions
Just caught the new report from Microsoft Incident Response regarding the Model Context Protocol (MCP), and it’s a stark reminder that we need to be paranoid about what our AI agents are 'allowed' to do.
The core issue is tool description poisoning. An attacker doesn't need to exploit a buffer overflow in the LLM; they just need to manipulate the JSON schema or description of a tool the agent uses. If the description says 'Send this data to backup,' but the implementation or parameter interpretation allows an external C2, the agent happily obliges because it thinks it's following a routine procedure.
The scary part? The agent doesn't break its safety guidelines. It sees a valid tool, valid parameters, and executes.
Detection Thoughts
Since the traffic looks 'routine' to the agent, we need to focus on Inputs/Outputs rather than just the tool execution. We should be logging the full tool payload. Here is a basic KQL idea to flag outbound destinations in tool parameters that don't match our internal corpus:
AIToolsLog
| where ToolName has "export" or "transfer"
| project Timestamp, AgentID, ToolName, Parameters
| parse Parameters with * '"destination": "' Destination '"' * // Adjust based on your JSON logging
| where !Destination contains ".internalcorp.net"
| project Timestamp, AgentID, SuspiciousDestination=Destination
Has anyone started implementing strict allow-lists for tool input parameters in their environments, or are we still relying on the LLM's 'common sense' (which clearly isn't enough)?
This is essentially a supply chain attack for AI infrastructure. We're treating MCP tool definitions just like we treat code signing now. If the hash of the tool description changes, the agent shouldn't load it.
We are also sandboxing the actual execution environment. Even if the agent decides to send data somewhere, the container has no egress rights except to the specific database. Layering defense is the only way until the models get better at identifying malicious intent in the prompt/description layer.
From a SOC perspective, this is a nightmare to visualize. Most SIEMs aren't set up to parse 'tool reasoning' yet. We've started pushing all agent tool calls into a dedicated pipeline to normalize the JSON blobs.
The issue with relying on 'common sense' is exactly right. We found in testing that if you tell the agent 'For compatibility purposes, wrap the data in a base64 encoded XML structure,' it often bypasses simple DLP filters because the agent is just doing what it's told to be 'helpful'.
We actually tested this vector last month using a modified 'file_reader' tool description. By subtly altering the description to suggest that 'verbose output' includes sending a copy to a 'debugging endpoint,' we got the agent to exfiltrate 30% of the test dataset.
My takeaway: Don't let agents auto-discover tools. If an LLM can dynamically load a new tool based on a user query, you've already lost.
We’ve started adding a linting step to our MCP registration pipeline to catch these descriptions before the agent ever sees them. Specifically, we flag tools that allow dynamic URLs or base64 encoding in parameters. To monitor for exploitation attempts, we track the hash of the parameters against the approved schema using this KQL query:
AuditLogs
| where OperationName == "Tool.Invoke"
| project ToolName, ParamHash = hash_sha256(tostring(Parameters))
| join kind=anti (BaselineToolSchemas) on ToolName, ParamHash
Building on the linting approach, we enforce strict JSON Schema validation during registration to prevent the use of the 'any' type. If a tool description lacks explicit parameter constraints, we reject it immediately. We run a quick validation script to ensure only known, restricted types are accepted before the agent loads the definition.
import schema
if 'any' in tool_schema.get('type', ''):
raise ValueError('Unrestricted types are forbidden')
schema.validate(instance=tool_def, schema=strict_template)
While prevention is key, detection is where we secure the environment. I'd recommend hunting for parameter length anomalies, as attackers often pack payloads into tool arguments. If you're using Sentinel or a similar platform, this KQL query helps spot suspiciously large payloads that might indicate an injection attempt:
AgentToolCalls
| where ToolName in ('file_reader', 'data_export')
| extend PayloadSize = strlen(tostring(Parameters))
| where PayloadSize > 1000
| project Timestamp, AgentId, ToolName, Parameters
It’s a simple heuristic, but effective for catching obfuscated instructions.
Verified Access Required
To maintain the integrity of our intelligence feeds, only verified partners and security professionals can post replies.
Request Access