MCP-beveiliging: AI-agents toegang geven tot bedrijfssystemen zonder tokens te delen
Wat de MCP-spec zegt over OAuth, audience binding en token passthrough, en een gatewaypatroon dat AI-agents toegang per persoon geeft met volledige auditlog.
De meeste teams koppelen hun eerste MCP-server op één namiddag. Iemand maakt een personal access token aan, plakt die in het configuratiebestand van Claude Desktop, Cursor of VS Code, en plots kan de agent tickets lezen, een database bevragen of pull requests openen. Dit artikel bekijkt wat er mis is met die opzet, wat de specificatie van het Model Context Protocol zegt over autorisatie, en een patroon waarmee agents bedrijfssystemen bereiken zonder dat iemand een token in een JSON-bestand kopieert.
Alle verwijzingen naar de specificatie gaan over revisie 2026-07-28, die modelcontextprotocol.io op het moment van schrijven (29 september 2026) als huidige versie vermeldt.
Hoe de gebruikelijke opzet eruitziet
Een lokale MCP-server is een proces dat de client op je laptop start. De client geeft het credentials mee via omgevingsvariabelen. De README van de GitHub MCP-server toont bijvoorbeeld een lokale configuratie in deze trant:
{
"mcp": {
"servers": {
"github": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}" }
}
}
}
}Aan de server zelf is niets mis. De README van GitHub raadt minimale scopes en zorgvuldige opslag aan, en de remote server van GitHub ondersteunt OAuth als alternatief. Problemen beginnen wanneer dezelfde vorm zich herhaalt over tien tools en twintig mensen:
- Tokens met een lange levensduur staan in gewone configuratiebestanden en shellprofielen op elke laptop die ze gebruikt. Eén token vernieuwen betekent elke kopie opsporen.
- Tokens krijgen brede scopes, omdat niemand vooraf weet welke tools de agent zal aanroepen.
- Teams delen een token van een serviceaccount voor systemen waar individuele accounts omslachtig zijn, zodat het achterliggende systeem één identiteit ziet voor iedereen.
- De lokale server draait met dezelfde rechten in het besturingssysteem als de gebruiker, vaak met netwerktoegang tot interne systemen.
- Er bestaat geen centraal overzicht van welke persoon, met welke agent, welke tool met welke argumenten aanriep. De auditlog van de SaaS-dienst toont de eigenaar van de token, als hij al iets toont.
In mei 2025 beschreef Invariant Labs een aanval waarbij een kwaadaardige issue in een publieke GitHub-repository een agent opdroeg om gegevens uit de privérepository's van de gebruiker te halen en te publiceren. Volgens de onderzoekers lag de fout niet in de code van de GitHub MCP-server. Ze noemden het een architectuurprobleem op het niveau van het agentsysteem: de agent kon privérepository's bereiken die een taak in de publieke repository niet nodig had. Als maatregelen stelden ze beperktere rechten voor en een agent per sessie tot één repository te beperken. Ze merkten ook op dat veel gebruikers bij bevestigingen van tools op "Always Allow" klikken, waardoor die beveiliging wegvalt.
Ook de lokale tooling rond MCP had eigen bugs. CVE-2025-6514 in het npm-pakket mcp-remote maakte OS command injection mogelijk wanneer de tool verbinding maakte met een onbetrouwbare MCP-server, via een gemanipuleerde URL van het autorisatie-endpoint. De GitHub-advisory beoordeelt het als kritiek (CVSS 9,6) en vermeldt de versies 0.0.5 tot en met 0.1.15 als getroffen, met een fix in 0.1.16. Op een laptop waar ook een map vol API-tokens staat, betekent code-uitvoering dat die tokens ook blootliggen.
Wat de MCP-specificatie zegt over autorisatie
Het hoofdstuk over autorisatie is optioneel voor implementaties, en het geldt voor HTTP-transports. Voor stdio zegt de specificatie dat servers hun credentials uit de omgeving moeten halen, wat precies het lokale patroon hierboven is. Over HTTP met autorisatie ingeschakeld zijn de regels streng.
Rollen en discovery
Een beschermde MCP-server treedt op als OAuth 2.1 resource server. De MCP-client is een OAuth 2.1-client die handelt namens een resource owner, meestal de persoon achter het toetsenbord. Een aparte autorisatieserver geeft tokens uit, en dat kan je bestaande identiteitsprovider zijn. MCP-servers moeten OAuth 2.0 Protected Resource Metadata (RFC 9728) publiceren, en clients moeten dat document gebruiken om de autorisatieserver te vinden. In de praktijk krijgt een niet-geauthenticeerd verzoek een 401 met een WWW-Authenticate-header die naar /.well-known/oauth-protected-resource verwijst, en de client volgt die verder. Clients moeten waar mogelijk PKCE met S256 gebruiken, volgens de pagina over security considerations.
Audience binding en het verbod op token passthrough
Clients moeten de resource-parameter uit RFC 8707 (Resource Indicators) meesturen in zowel het autorisatieverzoek als het tokenverzoek, ingesteld op de canonieke URI van de MCP-server. Servers moeten controleren dat elke token voor hen als audience is uitgegeven en al het andere weigeren. De specificatie sluit ook een veelgebruikte shortcut uit: een MCP-server die een upstream API aanroept, heeft voor die API een eigen, aparte token nodig, en mag de token die hij van de client kreeg niet doorsturen.
Het document met security best practices noemt token passthrough, het doorgeven van tokens, "explicitly forbidden" en legt uit waarom. Passthrough slaat de rate limiting of validatie over die de MCP-server had moeten toepassen. Het maakt ook de audittrail onduidelijk: de MCP-server kan clients niet uit elkaar houden, en de achterliggende API logt een andere identiteit dan de server die het verzoek werkelijk stuurde. En een token die op meerdere plaatsen wordt aanvaard, laat een aanvaller die één dienst compromitteert doorstoten naar de andere.
Het confused deputy-probleem
Hetzelfde document beschrijft een confused deputy-aanval op MCP-proxyservers. De kwetsbare opzet is een proxy die één statische OAuth client ID gebruikt bij een API van een derde partij, MCP-clients zichzelf dynamisch laat registreren, en steunt op de consent-cookie van die derde partij. Een aanvaller registreert een client met een eigen redirect URI, stuurt de gebruiker een link, de derde partij slaat haar toestemmingsscherm over door de cookie, en de autorisatiecode belandt bij de aanvaller. De verplichte oplossing is toestemming per client op de proxy: houd per gebruiker een register bij van goedgekeurde client ID's, toon een toestemmingspagina die de client, de scopes en de redirect URI vermeldt, en valideer redirect URI's en de state-parameter exact.
Clientregistratie en scopes
Clients hebben een client ID nodig voor ze beginnen. De pagina over clientregistratie noemt drie mechanismen: voorafgaande registratie, Client ID Metadata Documents (de client gebruikt als ID een HTTPS-URL die naar zijn eigen metadata verwijst), en Dynamic Client Registration volgens RFC 7591. In 2026-07-28 staat Dynamic Client Registration als deprecated gemarkeerd en blijft het behouden voor achterwaartse compatibiliteit, en nieuwe implementaties worden naar Client ID Metadata Documents verwezen.
Voor scopes vraagt de specificatie dat servers de scopes die een verzoek nodig heeft aankondigen in de WWW-Authenticate-challenge, en dat clients enkel vragen wat ze nodig hebben. Wanneer een aanroep meer nodig heeft, antwoordt de server met 403 en insufficient_scope, en doorloopt de client een step-up-autorisatie. De pagina met best practices noemt wildcard-scopes en het vooraf publiceren van elke mogelijke scope als veelgemaakte fouten.
Menselijke controle
Het hoofdstuk over tools zegt dat er altijd een mens moet zijn die aanroepen van tools kan weigeren, en dat clients bij gevoelige handelingen om bevestiging moeten vragen en het gebruik van tools moeten loggen voor audit. Tools kunnen annotaties dragen zoals readOnlyHint en destructiveHint, maar het schema omschrijft die als hints waarop clients niet mogen vertrouwen wanneer ze van onbetrouwbare servers komen. De beslissing om een destructieve tool te blokkeren of te laten bevestigen moet dus genomen worden op een plek die jij beheert.
Voor organisaties met een centrale identiteitsprovider publiceerde het MCP-project in juni 2026 ook de extensie Enterprise-Managed Authorization. Daarmee beslist de IdP van het bedrijf welke MCP-servers een gebruiker kan bereiken, via een Identity Assertion JWT Authorization Grant die de client inruilt voor een token van de MCP-server.
Een praktisch patroon: toegang per persoon via een gateway
De specificatie levert de bouwstenen. Samengebracht voor een bedrijf met een handvol interne systemen en enkele SaaS-tools vormen ze een patroon dat er zo uitziet.
- Elke agent authenticeert zich als de persoon die hem gebruikt. De MCP-client doorloopt de OAuth-flow bij je identiteitsprovider, en de resulterende token is via de
resource-parameter gebonden aan de URI van de gateway. Er staan geen gedeelde tokens van serviceaccounts op laptops. - Upstream credentials blijven aan de serverkant. De gateway bewaart de API-sleutels of OAuth refresh tokens voor GitHub, Jira, het ERP of de database, of verkrijgt een token per gebruiker via een flow zoals OAuth 2.0 Token Exchange (RFC 8693). De token van de client wordt nooit doorgestuurd.
- Scopes worden per tool gedefinieerd. Tickets lezen en een project verwijderen zijn verschillende rechten, en de gateway toont enkel de tools die de scopes van de aanroeper toelaten. De specificatie laat uitdrukkelijk toe dat het resultaat van
tools/listverschilt naargelang de autorisatie van het verzoek. - Tools die schrijven of verwijderen staan standaard uit. Een nieuwe verbinding krijgt tools met alleen leesrechten, en schrijfrechten worden per groep toegekend of via step-up-autorisatie wanneer iemand ze nodig heeft.
- Aanroepen met een hoog risico vragen een menselijke beslissing. Betalingen, verwijderingen, wijzigingen aan rechten en bulkexports wachten tot de gebruiker of een aangewezen goedkeurder bevestigt. Deze controle gebeurt op de gateway, zodat ze niet afhangt van de instellingen van de client of van de eigen annotaties van een tool.
- Eén log registreert elke aanroep van een tool: de persoon, de agent of client ID, de tool, de argumenten (waar nodig afgeschermd), de beleidsbeslissing en het resultaat. Wanneer er iets misgaat, toont deze log welke persoon en welke agent de aanroep deed, wat de auditlog van de SaaS-dienst meestal niet kan.
Dit patroon sluit aan bij richtlijnen van buitenaf. De OWASP Top 10 for Agentic Applications for 2026, gepubliceerd in december 2025, telt Tool Misuse (ASI02) en Identity and Privilege Abuse (ASI03) onder haar categorieën. De eigen richtlijnen van de MCP-specificatie over scope minimization beschrijven hetzelfde progressieve model met minimale rechten: een kleine set scopes bij de start, met uitbreiding wanneer voor het eerst een bevoorrechte handeling wordt geprobeerd.
Lokale stdio-servers blijven zinvol voor tools die enkel de eigen machine van de ontwikkelaar raken. Daarvoor vraagt de specificatie dat clients het exacte commando tonen voor ze een nieuwe server starten, en dat ze die in een sandbox draaien. Alles wat een gedeeld bedrijfssysteem bereikt, hoort achter HTTP-autorisatie.
Checklist
- Inventariseer elke MCP-server die in gebruik is, lokaal en remote, en de credential die elk ervan bewaart.
- Verwijder personal access tokens en gedeelde sleutels van serviceaccounts uit configuratiebestanden van clients. Waar een leverancier een remote MCP-server met OAuth aanbiedt, gebruik je die.
- Publiceer voor je eigen HTTP MCP-servers Protected Resource Metadata, valideer de audience van de token, en weiger tokens die voor andere resources zijn uitgegeven.
- Stuur de token van de client nooit upstream door. Gebruik per upstream API een aparte credential of een token exchange.
- Als je een OAuth-proxy voor een API van een derde partij draait, implementeer dan toestemming per client en exacte controles van redirect URI's.
- Definieer scopes per tool, vermijd wildcard-scopes, en laat nieuwe gebruikers starten met tools met alleen leesrechten.
- Eis uitdrukkelijke goedkeuring voor destructieve aanroepen of aanroepen met een hoog risico, afgedwongen aan de serverkant.
- Log elke aanroep van een tool met persoon, client, tool, beslissing en uitkomst, en bewaar die logs waar je securityteam al kijkt.
- Houd de tooling van MCP-clients up-to-date, en behandel een verbinding met een onbekende MCP-server zoals het uitvoeren van onbekende code.
Wat we bouwen
Flowplane bouwt een MCP-endpoint dat dit patroon volgt: agents zullen zich aanmelden als de persoon die ze gebruikt, upstream secrets zullen op de gateway blijven, en elke aanroep van een tool zal gelogd worden met een persoon en een beleidsbeslissing. Het is nog niet beschikbaar, en we schrijven er hier over wanneer er iets uit te proberen valt.
Bronnen
- MCP-specificatie: versiebeheer (huidige revisie 2026-07-28)
- MCP-specificatie 2026-07-28: Authorization
- MCP-specificatie 2026-07-28: Authorization security considerations
- MCP-specificatie 2026-07-28: Client registration
- MCP-specificatie 2026-07-28: Tools
- MCP Security Best Practices
- MCP-blog: Enterprise-Managed Authorization (18 juni 2026)
- RFC 8707: Resource Indicators for OAuth 2.0
- RFC 9728: OAuth 2.0 Protected Resource Metadata
- RFC 8693: OAuth 2.0 Token Exchange
- Invariant Labs: GitHub MCP exploited (26 mei 2025)
- GitHub-advisory GHSA-6xpm-ggf7-wc3p (CVE-2025-6514, mcp-remote)
- OWASP Top 10 for Agentic Applications for 2026
- README van de GitHub MCP-server