Anthropic MCP Inspector의 인증 없는 RCE 취약점 탐지 템플릿을 작성해
projectdiscovery/nuclei-templates에 Merge됐다.
PR: #13142

취약점 개요

CVE-2025-49596는 Anthropic MCP Inspector 0.14.0 미만 버전에서 발생하는 인증 없는 원격 코드 실행(Unauthenticated RCE) 취약점이다. CVSS Critical 등급이다.

MCP Inspector는 MCP 서버를 테스트하고 디버깅하기 위한 개발자 도구다. 문제는 Inspector 클라이언트와 프록시 사이에 인증이 없다는 것이다. /sse 엔드포인트가 transportType, command, args[] 파라미터를 사용자 입력 그대로 받아서 처리하는데, 이 과정에서 임의 명령 실행이 가능하다.

GET /sse?transportType=stdio&command=<임의_명령>&args[]=<인자>

공격자가 이 엔드포인트에 접근 가능하다면 인증 없이 서버에서 임의 명령을 실행할 수 있다. API 키나 설정 파일 탈취, 내부 네트워크 피벗 등으로 이어질 수 있다.

MCP Inspector는 기본적으로 로컬 개발 환경에서 돌아가지만, 실수로 외부에 노출되거나 클라우드 환경에서 포트가 열린 채로 배포된 경우 원격 공격이 가능해진다.


왜 이 취약점에 템플릿을 작성했나

Prowler MCP를 직접 개발하면서 Inspector를 쓰고 있었다. CVE가 공개됐을 때 영향받는 버전을 쓰고 있었고, 취약점의 동작 방식이 명확해서 탐지 로직을 작성하기 적합했다. 또 nuclei-templates에 아직 템플릿이 없었다.

기여 자체가 목적이기도 했다. nuclei-templates는 전 세계 보안 엔지니어들이 실제로 쓰는 취약점 스캐너 템플릿 저장소다. 여기에 직접 작성한 탐지 로직이 머지되면 전 세계 Nuclei 사용자가 쓸 수 있게 된다.


템플릿 설계

Nuclei 템플릿은 YAML로 작성한다. 이 취약점의 탐지는 단순히 /sse에 요청을 보내는 것만으로는 부족하다. 오탐(false positive)을 줄이고 실제로 취약한 버전인지, 취약한 엔드포인트가 활성화되어 있는지를 단계적으로 검증해야 한다.

flow 키워드로 3단계 HTTP 요청이 모두 성공해야 취약으로 판정하도록 구성했다.

flow: http(1) && http(2) && http(3)

Step 1: MCP Inspector 확인

yaml

- method: GET
  path:
    - "{{BaseURL}}"
  matchers:
    - type: dsl
      dsl:
        - status_code == 200
        - contains(body,"MCP Inspector")
      condition: and
  internal: true
  extractors:
    - type: regex
      name: js
      group: 1
      part: body
      regex:
        - 'src="([^"]+\.js)"'
      internal: true

응답에 "MCP Inspector" 문자열이 포함되어 있는지 확인하고, JS 번들 파일 경로를 추출한다. MCP Inspector가 아닌 서버에서 오탐이 나지 않도록 하는 첫 번째 필터다.

Step 2: 버전 확인

yaml

- method: GET
  path:
    - "{{BaseURL}}{{js}}"
  matchers:
    - type: dsl
      dsl:
        - status_code == 200
        - compare_versions(version, '< 0.14.0')
      condition: and
  internal: true
  extractors:
    - type: regex
      name: version
      internal: true
      group: 1
      part: body
      regex:
        - 'const\s+version\s*=\s*"([0-9]+\.[0-9]+\.[0-9]+)'

Step 1에서 추출한 JS 파일을 가져와서, 소스 안에 있는 버전 문자열을 정규표현식으로 파싱한다. compare_versions(version, '< 0.14.0')로 취약한 버전인지 판단한다.

Step 3: 취약 엔드포인트 동작 확인

yaml

- method: GET
  path:
    - "{{BaseURL}}/sse?transportType=stdio&command=echo&args[]=hello-from-brower"
  matchers:
    - type: dsl
      dsl:
        - contains_all(body,"endpoint","/message?sessionId=")
        - status_code == 200
      condition: and
  extractors:
    - type: regex
      name: session_id
      part: body
      group: 1
      regex:
        - '\/message\?sessionId=([a-z0-9-]+)'

실제 /sse 엔드포인트에 echo 명령을 보낸다. 응답에 sessionId가 포함된 /message?sessionId= 형태의 엔드포인트가 반환되면 취약점이 실제로 활성화된 상태임을 확인한 것이다.

echo 명령을 사용한 이유는 non-destructive하기 때문이다. 서버 상태를 바꾸거나 파일을 생성하거나 네트워크 요청을 만들지 않고, 단순히 문자열을 출력해서 명령 실행 가능 여부만 확인한다.


리뷰 과정

PR을 올린 후 maintainer인 pussycat0x가 flow 로직을 업데이트했고, DhiyaneshGeek이 취약점 상세 정보와 remediation을 보완했다. 포매팅 수정 후 9월 15일에 머지됐다.

총 8개 커밋이 쌓였다. 처음 작성한 템플릿에서 maintainer들이 직접 개선을 붙여주는 방식으로 진행됐다. 리뷰 과정에서 내가 작성한 로직은 크게 변경되지 않고 flow 구조와 메타데이터 부분이 정리됐다.


기여 후 템플릿 사용법

머지됐으니 nuclei-templates를 최신으로 업데이트하면 바로 쓸 수 있다.

bash

# 템플릿 업데이트
nuclei -update-templates

# MCP Inspector 취약점 스캔
nuclei -t http/cves/2025/CVE-2025-49596.yaml -u http://target:5173

MCP Inspector가 기본적으로 5173 포트를 사용하므로, 내부망 스캔이나 클라우드 환경 점검에서 이 포트를 대상으로 실행하면 된다.


패치 정보

0.14.1 이상으로 업그레이드하면 해결된다.

bash

npm install -g @modelcontextprotocol/inspector@latest

MCP Inspector를 개발 도구로 쓰고 있다면 버전 확인 먼저.

bash

npx @modelcontextprotocol/inspector --version

PR: projectdiscovery/nuclei-templates #13142
CVE: NVD CVE-2025-49596
참고: Oligo Security 분석글

Merge 됐다!