FlawOpen

flawopen.com/AI Security/mcp-typescript-sdk-bearer-token-audience-validation

● CWE-863 · CVSS 6.8 · 보통
보안 연구 · FlawOpen

MCP TypeScript SDK의 Bearer 토큰 Audience 검증 누락

GHSA-rvq5-wwqv-78pq는 Audience를 확인하지 않고 토큰을 수락하는 MCP HTTP 서버에 영향을 줍니다. 업데이트 후 expectedResource를 활성화하고 검증된 Audience를 AuthInfo.resource로 반환하세요.[1]

💡 알기 쉬운 설명 (ELI5)

경비원이 유효한 출입증을 받지만 어느 건물에 들어갈 수 있는지 확인하지 않는 상황입니다. 한 발급자가 여러 건물의 출입증을 발급하면 옆 건물용 출입증도 통과할 수 있습니다. MCP 서버는 출입증의 목적지를 자체 리소스 URL과 비교해야 합니다.[1]

핵심 개념 및 용어

Audience (`aud`)
액세스 토큰이 발급된 리소스 또는 서비스입니다. 서명이 유효하거나 introspection이 성공해도 이 MCP 서버를 위한 토큰이라는 뜻은 아닙니다.[1], [7]
`expectedResource`
수정된 middleware에서 명시적으로 활성화하는 설정입니다. 설정된 리소스 URL과 토큰 verifier가 보고한 리소스를 비교하며, 다르면 HTTP 401로 거부합니다.[1], [2], [7]
`AuthInfo.resource`
신뢰할 수 있는 토큰 검증 또는 introspection 데이터에서 verifier가 도출한 리소스 URL입니다. 검사를 활성화하면 수정된 middleware에 이 값이 필요하며, 없으면 요청이 거부됩니다.[1], [2], [7]
영향받는 패키지
권고문은 @modelcontextprotocol/sdk 1.6.0–1.31.0, @modelcontextprotocol/server 2.0.0–2.2.0, @modelcontextprotocol/express 2.0.0–2.0.1, @modelcontextprotocol/server-legacy 2.0.0–2.3.0을 다룹니다. CVE는 없으며 공급자가 CWE-863으로 분류했습니다.[1], [3], [6]

프레임워크 매핑

  • 이 가이드에서 설명하는 약점의 CWE 참조: CWE-863

단계별 공격 실행 흐름

단계 1

하나의 발급자가 여러 API 토큰을 발급

영향받는 배포는 MCP HTTP Bearer 인증을 사용하며, 인증 서버가 여러 서비스용 토큰을 발급합니다. 다른 API용 토큰도 서명이 올바르고 만료되지 않았을 수 있습니다.[1]

단계 2

토큰은 검증하지만 목적지는 확인하지 않음

영향받는 통합의 requireBearerAuth() / verifyBearerToken()에는 예상 리소스 검사가 내장되어 있지 않았습니다. 애플리케이션의 verifyAccessToken()도 aud를 확인하지 않으면 다른 서비스용 토큰을 MCP 서버가 수락할 수 있습니다.[1], [2], [5]

단계 3

다른 서비스 토큰이 MCP 권한 확인에 도달

다른 서비스의 유효한 토큰을 보유한 호출자가 이 MCP 서버에서 인증된 것으로 처리될 수 있습니다. 권고문은 CVSS 3.1 6.8 및 CWE-863을 지정했으며, 실제 악용 사례는 언급하지 않습니다.[1], [4]

단계 4

업데이트하고 MCP 리소스에 검증을 바인딩

수정 버전을 사용하고 expectedResource를 이 서버의 리소스 식별자로 설정한 뒤, verifyAccessToken()이 검증된 Audience를 AuthInfo.resource로 반환하게 하세요. 업데이트만으로 옵션이 켜지지는 않습니다. resource가 없으면 모든 요청이 401을 받습니다.[1], [2], [5], [3], [6], [7]

영향받는 MCP TypeScript SDK 패키지

패키지영향 버전수정 버전
@modelcontextprotocol/sdk1.6.0–1.31.01.32.0 이상
@modelcontextprotocol/server2.0.0–2.2.02.3.0 이상
@modelcontextprotocol/express2.0.0–2.0.12.0.2 이상
@modelcontextprotocol/server-legacy2.0.0–2.3.02.3.1 이상
verifyAccessToken()에서 자체 aud 검증을 수행하는 모든 패키지애플리케이션이 helper에 없는 검사를 이미 구현했을 수 있습니다.비교가 정확히 일치하고 의도한 리소스 식별자를 사용하는지 확인하세요.

소스 코드 비교: 취약한 구현 vs 보안 패치

이 예시는 SDK 문서 형식과 병합된 수정 사항을 따릅니다. verifyJwt는 애플리케이션에 이미 있는 JWT 검증기 또는 introspection 호출을 나타냅니다. 수정 전 middleware에는 expectedResource가 없었고 Audience를 비교하지 않았습니다. 수정 버전은 구성된 resource와 AuthInfo.resource를 비교합니다. Authorization server가 aud에 넣는 정확한 식별자를 사용하세요. 예시는 같은 origin의 Audience URL을 선택한 뒤 전체 resource 비교를 SDK에 맡깁니다. SDK 1.x는 1.32.0 이상으로, 2.x는 @modelcontextprotocol/server 2.3.0 이상으로 업데이트하세요. Express에서는 @modelcontextprotocol/express도 2.0.2 이상이어야 합니다. AuthInfo.resource는 URL 타입이므로 URL이 아닌 일반 aud 값은 expectedResource로 비교할 수 없습니다. 그런 배포에서는 verifyAccessToken() 안에서 해당 식별자를 엄격하게 검증하고 expectedResource를 설정하지 마세요. verifyJwt 구현은 애플리케이션별 코드이므로 생략했으며, 토큰 위조나 악용 절차는 포함하지 않습니다.[1], [2], [5], [3], [6], [7]

취약한 구현
import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';

const mcpServerUrl = new URL('https://api.example.com/mcp');
const auth = requireBearerAuth({
  verifier: {
    async verifyAccessToken(token) {
      const payload = await verifyJwt(token); // 애플리케이션 JWT 검증
      return {
        token,
        clientId: payload.sub,
        scopes: payload.scopes,
        expiresAt: payload.exp,
        // 여기서는 resource를 반환하지 않으며, 영향을 받은 helper에는 expectedResource 옵션도 없었습니다.
      };
    },
  },
});
보안 강화 패치
import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';

const mcpServerUrl = new URL('https://api.example.com/mcp');
const auth = requireBearerAuth({
  verifier: {
    async verifyAccessToken(token) {
      const payload = await verifyJwt(token); // 애플리케이션 JWT 검증
      // aud는 문자열, 목록 또는 누락된 값일 수 있습니다. 이 서버의 항목을 반환합니다.
      const audience = [payload.aud ?? []].flat().find(
        aud => URL.canParse(aud) && new URL(aud).origin === mcpServerUrl.origin,
      );
      const resource = audience ? new URL(audience) : undefined;
      return {
        token,
        clientId: payload.sub,
        scopes: payload.scopes,
        expiresAt: payload.exp,
        resource,
      };
    },
  },
  expectedResource: mcpServerUrl,
});

엔지니어링 및 시스템 보안 강화 체크리스트

출처

← AI Security Directory →