{"id":"CVE-2026-111771","kind":"vulnerability","aliases":["CVE-2026-111771","GHSA-rvq5-wwqv-78pq"],"related":[],"title":"MCP TypeScript SDK: Server bearer authentication accepted tokens issued for another service","description":"### Summary\nIn affected versions, the SDK's server-side bearer authentication had no way to check that a token was issued for your server (its audience). Where one authorization server issues tokens for several services, a valid token for another service was also accepted by your MCP server.\n\n### Am I affected?\nYes, if your HTTP server uses `requireBearerAuth()` or `verifyBearerToken()`, its authorization server also issues tokens for other services, and your `verifyAccessToken()` does not check the token's audience (`aud`) itself.\n\nAffected versions:\n\n- `@modelcontextprotocol/sdk` 1.6.0 through 1.31.0\n- `@modelcontextprotocol/server` 2.0.0 through 2.2.0\n- `@modelcontextprotocol/express` 2.0.0 through 2.0.1\n- `@modelcontextprotocol/server-legacy` 2.0.0 through 2.3.0\n\n### Fix\nUpgrade to:\n\n- 1.x: `@modelcontextprotocol/sdk` 1.32.0 or later\n- 2.x: `@modelcontextprotocol/server` 2.3.0 or later, together with `@modelcontextprotocol/express` 2.0.2 or later if you use it\n- `@modelcontextprotocol/server-legacy` 2.3.1 or later\n\n**Upgrading alone changes nothing.** The patched versions add an `expectedResource` setting that is off by default. To turn the check on, make both of these changes together:\n\n1. Pass the audience your authorization server puts in tokens for your server: `requireBearerAuth({ verifier, expectedResource: new URL('https://mcp.example.com/mcp') })`.\n2. Return the token's audience from `verifyAccessToken()` as `AuthInfo.resource`, also a `URL`.\n\nA token for another service then gets `401`. With only the first change, every request gets `401`.\n\nIf you cannot upgrade yet, reject any token whose `aud` does not include your server inside `verifyAccessToken()`. That closes the issue on every version.","summary":"The MCP TypeScript SDK's server bearer-auth check did not verify that a token was issued for this server's audience, so a valid token issued for another service on the same authorization server was accepted. An attacker holding such a token from another service can call your MCP server as that user.","severity":"medium","cvss":6.800000190734863,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"@modelcontextprotocol/sdk","fixed":["1.32.0"],"affected":">= 1.6.0, < 1.32.0","ecosystem":"npm"},{"name":"@modelcontextprotocol/server","fixed":["2.3.0"],"affected":">= 2.0.0, < 2.3.0","ecosystem":"npm"},{"name":"@modelcontextprotocol/express","fixed":["2.0.2"],"affected":">= 2.0.0, < 2.0.2","ecosystem":"npm"},{"name":"@modelcontextprotocol/server-legacy","fixed":["2.3.1"],"affected":">= 2.0.0, < 2.3.1","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["ai-tooling","cwe-863","mcp","node","oauth","self-hosted","typescript"],"not_affected_if":["default-config-not-using-bearer-auth","single-service-authorization-server","stdio-transport"],"how_to_check":"Check whether your HTTP MCP server uses requireBearerAuth() or verifyBearerToken() and whether verifyAccessToken() checks the aud claim.\nCheck installed versions: npm ls @modelcontextprotocol/sdk @modelcontextprotocol/server @modelcontextprotocol/express @modelcontextprotocol/server-legacy","fix":"Upgrade @modelcontextprotocol/sdk to 1.32.0+, @modelcontextprotocol/server to 2.3.0+, @modelcontextprotocol/express to 2.0.2+, or @modelcontextprotocol/server-legacy to 2.3.1+; then pass expectedResource to requireBearerAuth() and return the token audience as AuthInfo.resource (both required).\nUntil upgraded, reject tokens whose aud does not include your server inside verifyAccessToken().","status":"open","published_at":"2026-10-20T19:43:36+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","triaged_at":"2026-10-23T20:56:14+00:00","updated_at":"2026-10-23T20:56:14+00:00","category":"ai-tooling","confidence":0.8,"triage":{"at":"2026-10-23T20:56:14Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade @modelcontextprotocol/sdk to 1.32.0+, @modelcontextprotocol/server to 2.3.0+, @modelcontextprotocol/express to 2.0.2+, or @modelcontextprotocol/server-legacy to 2.3.1+; then pass expectedResource to requireBearerAuth() and return the token audience as AuthInfo.resource (both required).\nUntil upgraded, reject tokens whose aud does not include your server inside verifyAccessToken().","reach":"internet","impact":"medium","summary":"The MCP TypeScript SDK's server bearer-auth check did not verify that a token was issued for this server's audience, so a valid token issued for another service on the same authorization server was accepted. An attacker holding such a token from another service can call your MCP server as that user.","category":"ai-tooling","who_cares":["mcp","typescript","node","oauth","self-hosted"],"confidence":0.8,"needs_auth":"yes","worst_case":"Attacker with a token for another service acts as that user on your MCP server.","analyst_note":"","how_to_check":"Check whether your HTTP MCP server uses requireBearerAuth() or verifyBearerToken() and whether verifyAccessToken() checks the aud claim.\nCheck installed versions: npm ls @modelcontextprotocol/sdk @modelcontextprotocol/server @modelcontextprotocol/express @modelcontextprotocol/server-legacy","needs_analyst":false,"not_affected_if":["default-config-not-using-bearer-auth","single-service-authorization-server","stdio-transport"],"user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000655,"input_tokens":3597,"output_tokens":590,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-111771':15A,23A '-2026':14A,22A '-863':32B '/mcp'')':271C '1':198C,251C '1.31.0':182C '1.32.0':201C '1.6.0':180C '2':204C,272C '2.0.0':184C,188C,192C '2.0.1':190C '2.0.2':213C '2.2.0':186C '2.3.0':194C,207C '2.3.1':221C '401':292C,301C '78pq':20A 'accept':7A,77B,139C 'add':231C 'affect':97C,146C,177C 'ai':29B 'ai-tool':28B 'alon':225C 'also':138C,159C,282C 'anoth':11A,69B,85B,135C,288C 'attack':79B 'aud':175C,311C 'audienc':62B,121C,174C,254C,277C 'auth':48B 'authent':6A,106C 'authinfo.resource':281C 'author':74B,124C,157C,256C 'bearer':5A,47B,105C 'bearer-auth':46B 'call':88B 'cannot':304C 'chang':226C,249C,297C 'check':49B,111C,170C,243C 'close':320C 'cve':13A,21A 'cwe':31B 'default':239C 'everi':298C,324C 'expectedresourc':233C,266C 'first':296C 'fix':195C 'get':291C,300C 'ghsa':17A 'ghsa-rvq5-wwqv-78pq':16A 'hold':80B 'host':38B 'http':150C 'includ':314C 'insid':317C 'issu':9A,57B,67B,116C,126C,160C,322C 'later':203C,209C,215C,223C 'make':245C 'mcp':1A,33B,41B,90B,142C 'mcp.example.com':270C 'mcp.example.com/mcp'')':269C 'modelcontextprotocol/express':26A,187C,212C 'modelcontextprotocol/sdk':24A,179C,200C 'modelcontextprotocol/server':25A,183C,206C 'modelcontextprotocol/server-legacy':27A,191C,220C 'new':267C 'node':34B 'noth':227C 'oauth':35B 'one':123C 'pass':252C 'patch':229C 'put':258C 'reject':307C 'request':299C 'requirebearerauth':153C,264C 'return':273C 'rvq5':18A 'sdk':3A,43B,100C 'self':37B 'self-host':36B 'server':4A,45B,60B,75B,91B,103C,119C,125C,143C,151C,158C,257C,263C,316C 'server-sid':102C 'servic':12A,70B,86B,130C,136C,164C,289C 'set':234C 'sever':129C 'side':104C 'summari':95C 'togeth':210C,250C 'token':8A,55B,66B,83B,114C,127C,133C,161C,172C,260C,275C,286C,309C 'tool':30B 'turn':241C 'typescript':2A,39B,42B 'upgrad':196C,224C,305C 'url':268C,284C 'use':152C,218C 'user':94B 'valid':65B,132C 'verifi':52B,265C 'verifyaccesstoken':167C,279C,318C 'verifybearertoken':155C 'version':98C,178C,230C,325C 'way':109C 'whose':310C 'wwqv':19A 'x':199C,205C 'yes':147C 'yet':306C","nicknames":[],"mitigations":[],"who_affected":null,"tier":"B","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-20T19:43:36+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-rvq5-wwqv-78pq","url":"https://github.com/advisories/GHSA-rvq5-wwqv-78pq","severity":"medium","published_at":"2026-10-20T19:43:36+00:00","modified_at":"2026-10-20T19:43:37+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","fetched_at":"2026-10-23T19:11:32+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}