# Specifikace MCP na SSRF myslí. Jen z druhé strany drátu

*Stratt Labs*

Bezpečnostní dokument specifikace MCP má vlastní sekci o SSRF. Najdete v ní pět útočných vzorů i mitigace, které fungují. Celá je ale napsaná o klientovi, který stahuje cizí adresy během OAuth discovery.

Server, jehož nástroj dostane URL jako parametr, v ní není. A přesně takové servery se letos v červenci proměřily v provozu.

## Co v té sekci opravdu stojí

Dokument `Security Best Practices` ([revize 2026-07-28](/journal/mcp-server-legacy-migrace-2026/), staženo 10. září 2026) vypisuje pět vzorů, kterými se dá kontrola cíle obejít: přímá adresa do vnitřní sítě, cloudová metadata na `http://169.254.169.254/`, služby na localhostu (v příkladu Redis na `http://localhost:6379/`), DNS rebinding a řetěz přesměrování, tedy "Normal-looking URLs that redirect to internal resources".

Mitigace, které k tomu dává, jsou věcné. Blokovat celé rozsahy, a to takto vyjmenované: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `127.0.0.0/8`, `::1`, `169.254.0.0/16`, `fc00::/7`, `fe80::/10`. Ten výčet je práce autorů MCP. RFC 9728, na které se u něj odkazují, v sekci 7.7 rozsahy nevypisuje - doporučuje jen "blocking requests to internal IP address ranges" a posílá čtenáře na OWASP. K tomu jedna poznámka, která stojí za přečtení dřív, než si takovou kontrolu začnete psát sami:

> "Avoid implementing IP validation manually. Attackers exploit encoding tricks (octal, hex, IPv4-mapped IPv6) that custom parsers often miss."

A dvě další, obě správné a obě se běžně vynechávají: *"Apply HTTPS and IP range restrictions to redirect destinations"*, respektive *"Consider disabling automatic redirect following and validating each hop"*. A u DNS: *"Consider pinning DNS resolution results between check and use"*, protože mezi kontrolou a stažením se odpověď DNS může změnit.

To je dobrý seznam. Není to seznam, který by chyběl.

## Směr, který v něm není

Vezměte první větu té sekce o mitigacích:

> "MCP clients deployed to a server MUST consider SSRF risks and implement appropriate mitigations when fetching OAuth-related URLs."

Klient. Model útoku je celou dobu stejný: nepřátelský MCP server podstrčí v hlavičce `WWW-Authenticate` nebo v metadatech adresu do vnitřní sítě a klient ji poslušně stáhne. Druhá podsekce ten model rozšiřuje na autorizační server, který si stahuje `Client ID Metadata Document`. Obojí je reálné a obojí do toho dokumentu patří. Sám o sobě říká, že je "complementing the MCP Authorization specification".

Celý ten dokument má jedenáct sekcí o útocích: Confused Deputy, Token Passthrough, SSRF, State Handle Hijacking, Local MCP Server Compromise, OAuth Authorization URL Validation, stdio Transport Security in Proxy Scenarios, Mix-Up Attacks, Localhost Redirect URI Impersonation, CIMD Trust Policies, Scope Minimization. Je to úplný výčet. Ani jedna z těch sekcí se nezabývá adresou, která do serveru přiteče jako argument nástroje; řetězec `tool input` ani `tool arguments` se v dokumentu nevyskytuje.

Stejná díra je i o patro níž. Oficiální konformní sada pro tuhle revizi má scénář `dns-rebinding-protection` - tedy zase obranu *klienta*. Kdo ji projde, ví, že mluví protokolem správně; o tom, kam jeho nástroj umí sáhnout, mu neřekne nic. [Psali jsme o tom rozdílu zvlášť](/journal/konformita-neni-prijeti-do-katalogu/): projít testy a být přijat katalogem jsou dvě různé věci, a bezpečnost serveru je třetí.

Přitom je to úplně obyčejný případ. `fetch_page`, `check_feed`, `validate_sitemap`, `import_from_url`, `screenshot`. Jakmile takový nástroj vystavíte, je váš server HTTP proxy, kterou obsluhuje kdokoli, jehož agent s ním mluví.

Dvě věci k tomu na straně serveru přistupují navíc.

Volající nemusí být člověk, který to zkusí. Argument nástroje vybírá model a ten čte cizí text. Stránka, kterou si agent otevřel cestou, umí navrhnout, co do parametru dát.

A druhá: server obvykle stojí tam, kde má do sítě větší dosah než volající. Runner v CI, kontejner ve VPC, notebook v domácí síti s administrací routeru na druhé straně. Kontrola perimetru je v takové chvíli k ničemu, protože požadavek vychází zevnitř.

## Není to hypotéza

V červenci 2026 proběhlo první dynamické měření internetových MCP serverů. Nicolás Padilla (CobaltoSec, samostatný výzkumník) zveřejnil 31. července preprint `Exposed by Design` na arXivu pod číslem 2608.00150. Není to recenzovaná studie ani práce z univerzitní laboratoře, což je při čtení čísel dobré vědět.

Čísla z abstraktu: přes 21 000 instancí serverů detekovatelných z veřejného internetu, **640 potvrzených produkčních serverů, 414 z nich dynamicky auditovaných a 68 reportovatelných zranitelností**. Mezi nimi SQL injection, prompt template injection, path traversal a *"SSRF targeting cloud metadata services"*.

Ta část metodiky míří přesně na server, jehož nástroj bere URL jako parametr:

> "For servers exposing tools that accept URL parameters, Corvus issues calls with the parameter set to http://169.254.169.254/latest/meta-data/ (AWS IMDS), http://metadata.google.internal/, and a controlled researcher-owned endpoint."

Jeden potvrzený nález je v práci doložený časem odpovědi: **11,9 sekundy proti základní hodnotě 0,3 sekundy**. Server tedy někam sáhl a čekal. Cílem byla metadatová služba AWS, tedy místo, odkud se běžně čtou dočasné přístupové klíče k účtu.

Dvě čísla ze stejného abstraktu, která říkají něco o stavu ekosystému. **91,8 % dynamicky auditovaných serverů nemá OAuth** - pozor, ten podíl se počítá ze 414 auditovaných, ne ze 640 potvrzených; některé převzaté články to zaměňují. A **41,6 % potvrzených serverů zmizí do tří dnů** mezi dvěma měřeními, což autor čte jako nasazování bez bezpečnostní revize.

Nezávislé potvrzení existuje, měří ale něco jiného. Zhou a kolektiv (arXiv 2605.22333, květen 2026) našli 7 973 živých vzdálených serverů a u **40,55 % z nich nástroje bez jakéhokoli ověření**. To není totéž jako `bez OAuth`: server se statickým API klíčem se počítá do Padillových 91,8 %, ale ne do těch 40,55 %. Ta dvě čísla se nesčítají ani nezaměňují.

## Kontrola, která obstojí

Šest bodů. Prvních pět má oporu ve zdrojích výše, šestý je náš názor.

**1. Kontroluj v okamžiku stahování, ne na vstupu.** Validace ve formuláři nebo ve schématu nástroje je pohodlí pro volajícího, ne obrana. V edge runtime se navíc jméno na IP spolehlivě nepřeloží, takže na vstupu umíte odmítnout jen doslovné adresy. Kontrola patří k tomu řádku, který otevírá spojení.

**2. Rozřeš jméno na IP a odmítni celé rozsahy - knihovnou, ne regulárním výrazem.** Kromě rozsahů z RFC 9728 dopadá do stejné kategorie i sdílený prostor poskytovatelů `100.64.0.0/10`. A hlídejte zápisy, na které ruční kontrola nemyslí. Pět příkladů, které všechny míří na loopback `127.0.0.1` a všechny projdou seznamem zakázaných řetězců: `127.1`, `0x7f.1`, `2130706433`, `[::ffff:127.0.0.1]` a `64:ff9b::7f00:1` (loopback zabalený do prefixu NAT64).

**3. Revaliduj cíl znovu při přesměrování.** Kontrola prvního skoku je divadlo: útočník pošle běžnou doménu, ta vrátí 302 na vnitřní adresu a jste tam, kde jste byli. Buď přesměrování nesledujte automaticky, nebo kontrolujte skok po skoku.

**4. Připoj se na tu IP, kterou jsi ověřil.** Když po kontrole resolvujete podruhé, nepřátelský DNS vrátí napoprvé veřejnou adresu a napodruhé loopback. Adresu je potřeba mezi kontrolou a použitím podržet. Řada HTTP klientů to umí, jen se to musí zapnout - a když to váš klient neumí, je lepší to napsat do dokumentace než předstírat, že je zavřeno.

**5. Egress mimo vlastní síť je druhá vrstva, ne oprava.** Pouštět stahování z vyhrazeného stroje je dobrý nápad a specifikace ho doporučuje také (jmenuje Smokescreen od Stripe). Ale kdyby se spoléhalo jen na ni, chyba v ní stojí celou síť toho stroje. Kontrola cíle musí platit i tam.

**6. Odmítnutí nesmí být tiché.** Tenhle bod si píšeme sami. Když guard vyhodí chybu, která je podtřídou běžné síťové chyby, sebere ji první `except` v pořadí a cíl se do reportu zapíše jako `nedostupný`. Tichá obrana vypadá v logu stejně jako obrana, která tam není. Proto u sebe rozlišujeme vadu cíle od výpadku spojení a [metodiku máme zveřejněnou](/methodology/) - verdikt, který nejde ověřit, není verdikt.

## Co se za opravu nepočítá

Seznam zakázaných řetězců (`localhost`, `127.0.0.1`) odmítne přesně to, co nikdo posílat nebude. Sama specifikace to říká v poznámce citované výše.

Kontrola jen prvního skoku, viz bod 3.

Povolení schémat `http` a `https` bez kontroly cíle. Schéma neříká nic o tom, kam to vede.

A námitka, že to volá jenom váš vlastní agent. Ten endpoint stojí na veřejném internetu; těch 21 000 instancí z Padillovy studie někdo našel právě proto, že se najít daly.

Ten seznam není dlouhý. Je to den práce pro člověka, který ví, co má zkusit - a je to rozdíl mezi nástrojem, který stahuje stránky, a proxy do vaší sítě.

Psali jsme i o tom, [co obnáší provozovat MCP server v produkci](/journal/mcp-in-production/) - anglicky, o provozu, ne o bezpečnosti.

## Zdroje

- Model Context Protocol, `Security Best Practices`, revize 2026-07-28: https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices.md (staženo 10. 9. 2026)
- N. Padilla, *Exposed by Design: A Dynamic Security Assessment of Internet-Facing MCP Servers at Scale*, arXiv:2608.00150, 31. 7. 2026: https://arxiv.org/abs/2608.00150
- Zhou et al., *A First Measurement Study on Authentication Security in Real-World Remote MCP Servers*, arXiv:2605.22333, 21. 5. 2026: https://arxiv.org/abs/2605.22333
- RFC 9728, sekce 7.7: https://datatracker.ietf.org/doc/html/rfc9728#section-7.7
