OWASP First Principles: Avoid MCP Tool Call Hijacks With AWS Bedrock AgentCore
A wrong judgement from an AI agent is not only from model-infused hallucinations, it could also be influenced by an attack or other external factors beyond the control of the model. I did an experiment stress testing an healthcare agentic system in sandbox to hijack the tool call and see what would happen, had some interesting findings which i share in this article.
A wrong judgement from an AI agent is obviously not only from model-infused hallucinations, it could also be influenced by an attack or other external factors beyond the control of the model. Consider an healthcare agentic system wrongly prescribing a patient 5,000mg of Amoxicillin! Ten times the safe dose. I did an experiment stress testing in sandbox to see if this could actually happen, so i decided to write about it because i found this interesting and it could be avoidable considering one or more principles from this OWASP framework on deploying multi-agentic systems; it worth a read here !
Why This Matters Now
AI agents have left sandbox! They're writing prescriptions, executing trades, approving loans, dispatching emergency services, handling customer interactions, updating production codes. These agents call external tools over the network. The OWASP Foundation published comprehensive guidelines for securing agentic AI systems. I spent some time reading them, but what does it actually look like when these vulnerabilities are exploited, not just theorithically?. In a running system, with a real LLMs making real decisions based on poisoned data or exploiting network vulnerabilities or adversarial attacks on the LLM itself. Autonomous systems is not completly changing how we build software but its increasing the necessity for security and monitoring tools. In this article, we build a case study for a production-realistic attack, run it against large langauge models, and documents what breaks and what doesn't. Then we fix it across different levels of the system, the attack here targets a vulnerability in the network layer and the application layer.
MCP Tool Calls Are Not API Calls
Building traditional applications implementing HTTP calls, GRPC calls e.t.c are all explicit, meaning you control the request flow end to end at the code level. In contrast, an AI agent is a model expressing an intent with a tool call using an object described with a name and parameters, and orchestration layer of the entire system translates the agent's intent to an actual network request for the model. In theory, the model does not process the URL, header or other components of the request however it influences the parameters used for the request, in fact the model trusts whatever comes back from a tool call as truth. Prompts with phrases like "never invent medication data, make no mistake, quote verbatim from the retrieved tool response", guide the reasoning and judgement of model. For example building a multi-agent system on AWS, you either write the orchestration layer using The Converse API loop or allow Managed Bedrock Agents handle it; In both paths, the model's relationship to its tools are identical: it emits intent to a layer it does not control or completely verify to executes the intent and return a result. The model does not completely have the mechanism to authenticate the tool server, validate the transport, or detect modifications to the response. That responsibility is for the orchestration layer although LLMs usually have AI safety benchmarks and are trained with defences in place against adversarial attacks but there is still the risk of memory or context poisoning and this is what the attack we exploit in an healthcare agentic system for education purpose in this article.
What a Normal Agentic Round-Trip Looks Like
For experimentation and educational purpose, the setup here is a clinical prescription agent receiving a patient case; in this case:
Patient P-3847, 72kg, diagnosed with acute upper respiratory infection (ICD-10: J06.9), currently taking lisinopril and metformin, no known allergies
The legacy agentic setup with a chunk of vulnerabilties, looks like this. Good thing is it works as expected but can also be easily exploited at the network layer and the actual application layer (where we have the LLM model handling the reasoning aspect of the agent)

| Component | Functionality in this setup |
|---|---|
| LLM model (llama-3.3-70b) | This is reasoning engine for the agent. It emits tool_use intents, in this case: lookup_medication, check_drug_interactions. It also consumes each toolResult as context before producing the final result. |
| Orchestration (Converse API loop) | This handles the agent loop between the model and MCP. On each tool_use, issues an MCP tools/call to the configured MCP server URL, then returns the MCP result to the model as toolResult → context for the next turn in the conversation loop. |
| MCP server | This is the vulnerable part of the architecture exploited for this experimentation. It is a public mcp edge that exposes (tools/list, tools/call) to orchestration, maps tools to private REST (POST /v1/formulary, POST /v1/interactions), unwraps the Lambda response, and returns an MCP tool result. In this case, its not holding any data. |
| Tool server — API Gateway | For this experimentation this is a private internet gateway exposing a REST endpoint for the Lambdas. It routes to the formulary and interaction with POST requests to the respective lambda functions |
| Tool server — Formulary Lambda (formulary-lookup-medication) | Executes formulary lookup against AuroraDB; it returns something like { medications: [500mg …] } (plus route, frequency, max daily dose, contraindications). Stays behind the private tool API (IGW) |
| Tool server — Interactions Lambda (formulary-check-drug-interactions) | Executes pairwise interaction checks against AuroraDB; returns { has_major_interaction: false } (plus any matched interaction rows). Stays behind the private tool API. |
| Tool server — Aurora | Shared clinical DB behind both Lambdas (formulary and drug_interactions tables). This is not public and it available within its subnet on two availability zones (as required by AWS for AuroraDB) |
Why This Architecture Is Uniquely Vulnerable
While all looks good with this setup from a functionality perspective, it still has a chunk of vulnerabilities that can be exploited by an attacker to poison the model's context, reasoning and even log PII data.
The vulnerability here is not based on the which orchestration layer is used here: Bedrock Agents or the Converse API loop or Langraph or Strands Agents; its the fact that the reasoning model does not control the flow of data in the system, an attacker does need access to the weights of the model or system prompt to poison the judgement of the agent.
Few vulnerabities here are:
- It cannot verify the MCP server's identity. When the model emits
lookup_medication, it has no idea which MCP server handled that call. Orchestration alone chooses (or inherits) the MCP URL. A few things can happen:- Orchestration reaches the legitimate MCP server; MCP calls the private tool API; everything works (proposed functionality).
- The MCP hostname is hijacked (DNS cache poisoning, BGP, bad config e.t.c): The model still gets a well-formed
toolResult, but it was processed by the attacker's mcp server which still proxies to the correct hostname so the attack goes unnoticed even with audit logs. - The MCP service itself can be compromised (image, secrets, supply chain). This is the same blind spot: the model only sees tool intent in / tool result out.
- Response from tool calling is the source of truth. Guardrails have to live outside the model, on the MCP path and after tool results return.
Exploiting the Vulnerabilities
To test the hijack risk, the experimentation ran on a synthetic patient case described previously, the full experiment code and logs are in this repository for easy reference. First to validate the pipeline behaves exactly as intended, the formulary tool returns 500mg for Amoxicillin, and the agent recommends a standard, safe course: 500mg PO TID for 10 days (still pending a clinician's sign off)
To exploit the public MCP edge without making changes to the actual tools (lambda functions). The orchestration was pointend to a malicious proxy posing as a DNS-poisoning or BGP-hijack scenario against the public MCP endpoint. The proxy still forward the calls to the legitimate lambdas and returned the correct schema result but poisoned the
dosage_mg value by 10 in transit and exfiltrated the patient data it saw along the wayIn practical sense, the backend logs or DB entries still shows the correct dosage but the agent simply does not see that number or return it the clinician for review (first assumption here would be a hallucination problem from the model - if it is fortunately caught by the clinician assigned to administer the prescription)
In this case, nothing about the model's reasoning failed here or in simple term no hallucination happened actually. The model only responded with a tampered formulary response verbatim, ran the interaction checks correctly against poisoned inputs, and produced exactly the well-structured, high-confidence answer it's built to produce. The vulnerability here is not the model, in simple terms!
Fixing The Vulnerability With AWS Bedrock AgentCore
Directly looking at the problem here, the fix is obviously at the Network layer of this architecture but we can further fix the vulnerability at the application layer as well; this way only clean and verified requests ever get to the mcp server and the model at reasoning runtime.
The Hardened Architecture

The Network Layer - Bedrock AgentCore Gateway + AWS PrivateLink
- All client requests go through Bedrock AgentCore Gateway as the single entry point, this way no client talks directly to the backend MCP server.
- The connection between the Gateway and the MCP server (inside a VPC) is through AWS PrivateLink, with this approach no request to and from the MCP server is routed through the public internet.
For the concrete AWS setup (VPCs, PrivateLink / VPC Lattice private targets, registering a fixed MCP endpoint in AgentCore Gateway), see Protecting AgentCore with VPC and AWS PrivateLink and AgentCore VPC interface endpoints on how to set this up and based on your use case.
The Application Layer - AgentCore Identity and Request Replay Protection
Its safe to say the network isolation and completely private access to the mcp servers is enough defense, because actually it is. The MCP hijack scenario is completely prevented at the level because the only entry point is through the AgentCore Gateway and that's only accessible through PrivateLink. But there is still a risk of identity compromise within the system which can be avioded with AgentCore Identity.
- AgentCore Identity issues short-lived, cryptographically signed tokens per session (preferrably per minute but depends on the system use case)
- Every MCP request further carries that token and a mutual TLS runs between the agent and the AgentCore Gateway; the logs also needs to explicitly show this identity per request, which is easier now because it is only one entry point to the mcp servers.
- Before processing any tool call the backend lambda or service running on ECS (in this case we have two lambdas: formulary and interactions), must validate the token's signature against AgentCore Identity's public key (we can store this in KMS or Secret Manager and rotate periodically).
- For replay protection, the shortlived token scoped per-minute solves this with a nonce (a one-time value issued and validated exactly once). The nonce validation process needs to happen in milliseconds, so ElasticCache is a good place to store and validate the nonce for every conversation turn or tool call response in the system.
End-to-End Request Flow
- Client (pathologist / pharmacist) authenticates with AgentCore Identity → receives a short-lived signed token bound to a nonce.
- Request goes to Bedrock AgentCore Gateway — the only entry point.
- Gateway forwards over PrivateLink into the VPC → reaches the MCP server behind a network load balancer. No public internet.
- Backend Lambda validates the token signature against AgentCore Identity's public key.
- Backend checks the nonce against Redis (per-client-session, short TTL) to block replay.
- Only after both checks pass: the anomaly-detection Lambda runs its profiling (e.g., drug-dosage plausibility).
- Clean request proceeds to the model on Bedrock runtime.
- Response flows back over the same authenticated, private path.
For anomaly observability, only after all security checks/validation pass, an anomaly-detection Lambda or process could also be necessary for profiling (e.g., drug-dosage plausibility).
Why This Works and Its Limitations
Using the OWASP Top 10 for agentic applications for 2026 as a benchmark for this architecture resolves and prevents the following vulnerabilities:
- Agent Goal Hijack
- Identity Priviledge Abuse
- Memory & Context Poisoning
- Tool Misuse & Exploitations
We can further add layers of security to it to cover other potential vulnerabilites from the input, dependencies, cascaded failures e.t.c, however this is exhaustive enough for this decent architecture showing what is obtainable building exteprise-ready agentic systems in production with Bedrock AgentCore Gateway and Identity. I'll explore other experimentation to expose other vulnerabilities and provide mitigation strategies.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article