Part 1 of 7 · 3 min read
Overview
In this module you will
- Describe the authorization flow an MCP client runs against an HTTP server, step by step, from a
401to a working call, and say what each step is for. - List the checks a server must make on every token (signature, issuer, audience, expiry, scope) and the status code each failure gets.
- Design scopes for a server: minimal first, step-up when needed, and explain why a broad catalogue in the first challenge is a mistake.
- Explain why token passthrough is forbidden and what the confused deputy attack looks like on an MCP proxy.
- Defend the flow against a stolen code (PKCE), open redirects (exact matching), mix-up (the
isscheck) and SSRF (guarded discovery). - Recognise tool poisoning, rug pulls, cross-server shadowing and indirect injection, and say which controls help and what each costs.
- Give a complete answer to the level's interview question: how would you secure an MCP server that exposes internal data?
Module 3 ended with a promise: a server on the network needs more than a closed door. This module keeps it. There are two different problems, and they need different tools:
- Who is calling, and what may they do? A conventional problem. The answer is OAuth: tokens, audiences, scopes. It is well understood, and the specification mostly points at existing standards.
- Can the thing the model reads be trusted? A new problem. A tool's description, a tool's result and a web page are all text that the model may obey. No token says anything about that. The controls are about what the model is allowed to do after reading something untrusted.
Teams routinely solve the first and forget the second, or the other way round. A server with perfect OAuth that returns poisoned text to a model with powerful tools is still an incident.
About the examples, and about the protocol version
Everything runs offline in one process. There is no real network: servers, the authorization server and the "internal" machines are Python functions on a small simulated network, so attacks on discovery can be shown safely. The HTTP shapes are real (methods, status codes, headers, JSON), and one experiment puts the protected server on a real socket on 127.0.0.1 and reads the headers with Python's HTTP client.
What is imitated: the authorization server (single process, one shared signing key instead of public-key signatures, no real login, no refresh tokens), the browser and the person (a function that approves or declines), and, above all, the model. The poisoning experiments use a deliberately gullible scripted model that obeys any instruction it finds, with simple patterns. Real models behave differently and the numbers say nothing about how often a real model is fooled; hard exercise 2 measures that. What the experiments do show is where each control stops an attack when the model is fooled, what it costs, and how it is evaded. The token code is not reviewed for production; use a maintained OAuth library and authorization server.
The message shapes follow the specification pages I read on 24 October 2026: the authorization page and its sub-pages (server discovery, client registration, security considerations) and the security best practices page, under the site's draft path (revision 2026-07-28). Where a page gave no rule I chose one and say so. Tool poisoning is not described on those pages; it comes from published security research and general knowledge, and I flag it where it appears.