본문으로 건너뛰기
NEW · Blast Radius: 유출된 API 키 대응 플레이북 (AWS·GCP·Azure)
블로그로 돌아가기

MCP 서버의 API 키는 헤더가 아닌 대화창을 거쳐 전달됩니다

공식 MCP 레지스트리의 원격 서버마다 initialize 요청을 한 번씩 보냈습니다. 응답한 22,027곳 중 71.3%가 헤더 인증 없이 세션을 허용했고, 도구 인자로 전달되는 자격증명 필드는 3,705개였습니다. 그중 마스킹 대상으로 지정된 필드는 3개뿐이었습니다.

김동현
작성자
김동현
발행
10 분1,433 어절
Share:
MCP 서버의 API 키는 헤더가 아닌 대화창을 거쳐 전달됩니다

공식 MCP 레지스트리에 shpbl.com이라는 원격 서버가 등록되어 있습니다. 이 서버의 write_to_repo 도구는 저장소에 브랜치와 풀 리퀘스트(PR)를 생성합니다. 입력 스키마에는 github_token이라는 문자열 필드가 있습니다. 설명란에는 "Contents와 Pull requests 쓰기 권한이 있는 일회용 GitHub 토큰. 이 호출에만 쓰고 저장하지 않음"이라고 기재되어 있습니다. 즉, 사용자는 쓰기 권한이 있는 토큰을 대화창에서 직접 도구 인자(Argument)로 전달해야 합니다.

이 서버를 특별히 악의적인 서버라고 단정하는 것은 아닙니다. 해당 서버는 'GitHub App 설치'라는 더 안전한 대안도 함께 안내하고 있습니다. 다만 Cremit은 이러한 구조적 설계가 MCP 레지스트리 전체에서 얼마나 보편적인지 확인하고자 했습니다. 이에 따라 2026년 10월 6일과 7일 이틀간, 공식 레지스트리에 등록된 원격 MCP 서버 전체를 대상으로 전수 조사를 진행했습니다.

지난 9월 조사가 GitHub에 공개된 .mcp.json 같은 에이전트 설정 파일 내의 API 키를 집계한 '클라이언트 측' 접근이었다면, 이번 글은 그 반대편을 분석 대상으로 합니다. 즉, 설정 파일을 받아 동작하는 원격 서버가 사용자 자격증명(Credential)을 어떤 경로로 전달받는지 분석했습니다.

조사 대상과 방법

공식 레지스트리(registry.modelcontextprotocol.io) API에서 등록된 서버 40,252개의 메타데이터를 전수 수집했습니다. 그중 원격 엔드포인트 URL을 공개한 서버는 25,270개(고유 URL 기준 25,857개)였습니다.

각 엔드포인트에는 MCP 표준 핸드셰이크인 initialize 요청을 1회씩만 전송했습니다. 그리고 응답 상태 코드와 WWW-Authenticate 헤더를 바탕으로 인증 방식을 분류했습니다. HTTP 헤더 인증 없이 세션을 허용한 서버에 한해서만 tools/list, resources/list, prompts/list 3가지 목록 조회 요청을 전송했습니다. 이 셋은 모두 서버가 수행할 수 있는 기능을 확인하는 읽기 전용(Read-only) 요청입니다.

조사 과정에서 도구(Tool)는 일절 실행하지 않았습니다. 리소스 본문을 열람하거나 인증을 우회하려는 시도 역시 하지 않았습니다. 즉, 이 글의 모든 분석은 서버가 스스로 공개한 도구 이름, 설명, 입력 스키마를 바탕으로 진행한 정적 분석 결과입니다.

원격 서버 10곳 중 7곳은 헤더 인증을 요구하지 않았습니다

initialize 요청에 정상 응답한 서버는 총 22,027개였습니다. 연결할 수 없거나 404·5xx 오류를 반환한 엔드포인트는 분석 대상에서 제외했습니다.

initialize 요청에 응답한 원격 MCP 서버 22,027개의 인증 방식. 헤더 인증 없이 세션 발급 15,696개(71.3%), OAuth 요구 5,561개(25.2%), 기타 인증 요구 770개(3.5%)

이 중 15,696개(71.3%)는 아무런 자격증명 없이 세션을 허용했습니다. OAuth 기반의 401 Unauthorized 챌린지를 반환한 서버는 5,561개(25.2%)였고, 기타 방식으로 인증을 요구한 서버는 770개(3.5%)였습니다.

이 71.3%의 서버를 단순히 "보안이 취약한 서버"로 해석해서는 안 됩니다. 날씨나 공개 데이터처럼 원래 인증이 필요 없는 서비스도 많기 때문입니다. 더 중요한 점은 이들 중 상당수가 인증을 생략한 게 아니라는 사실입니다. HTTP 헤더 대신 다른 경로로 자격증명을 수신하고 있습니다.

인증 정보가 도구 인자(Argument)로 전달되고 있습니다

헤더 인증 없이 세션을 허용한 서버 중 13,610개가 도구 목록을 반환했습니다. 이들이 노출한 도구는 총 200,286개에 달합니다.

입력 스키마의 파라미터 이름을 분석하여 자격증명을 입력받는 필드를 식별했습니다(api_key, access_token, password, client_secret 등). 암호화폐 토큰 주소나 CSRF 토큰처럼 명칭만 유사한 필드 106건은 제외했습니다.

그 결과, 총 529개 서버, 3,582개 도구에 걸쳐 3,705개의 자격증명 입력 필드가 확인되었습니다.

파라미터 이름건수
api_key1,709건
apikey656건
password173건
session_token172건
access_token165건
auth_token138건
credential52건

이 3,705개 필드 중 JSON Schema에서 마스킹 대상으로 지정된 필드는 3개에 불과했습니다. 3개 모두 ship.page 서버의 password 필드로, writeOnly: true 속성이 부여되어 있었습니다.

JSON Schema에는 format: password나 writeOnly: true처럼 특정 필드가 민감 정보임을 나타내는 표준 키워드가 존재합니다. 클라이언트는 이 식별자를 보고 입력값을 마스킹하거나 로그에서 제외하는 보안 조치를 취할 수 있습니다. 하지만 이러한 지정이 없다면 클라이언트 입장에서는 해당 필드가 일반 검색어 입력란과 구별되지 않습니다.

더불어, 전체 필드 중 1,043개는 필수 입력(Required) 값이었습니다. 즉, API 키를 입력하지 않으면 해당 도구 자체를 사용할 수 없는 구조입니다.

도구 인자로 전달된 API 키의 노출 경로

API 키를 HTTP 헤더로 전송하면 키는 클라이언트 설정과 전송 계층(Transport Layer)에서만 처리됩니다. 그러나 도구 인자로 전달하는 순간 처리 경로가 달라집니다. 도구 인자는 LLM이 생성하는 값입니다. 모델이 도구 호출을 구성하려면 API 키가 프롬프트(대화 맥락)에 먼저 포함되어야 하기 때문입니다.

mcp.ledgerfc.com 서버의 한 필드 설명은 이 차이를 명확히 지적하고 있습니다.

"Authorization: Bearer 헤더로 전송하는 방식을 권장합니다. 이 경우 API 키가 대화 맥락에 포함되지 않습니다."
자격증명이 도구 인자일 때 API 키가 기록될 수 있는 세 지점. 입력, LLM 대화 기록, MCP 클라이언트의 요청·디버그 로그, 원격 서버가 받은 요청

도구 인자로 키를 전달할 경우, 자격증명이 노출될 수 있는 지점은 총 세 곳으로 늘어납니다. 첫째는 대화 기록(Conversation History)으로, 클라이언트 앱과 LLM 제공사(Provider) 양쪽에 기록됩니다. 둘째는 MCP 클라이언트의 요청·응답 로그와 디버그 로그입니다. 셋째는 원격 서버의 수신 로그로, 서버 운영자가 보관합니다.

서버 설명에 적힌 "키를 저장하지 않습니다"라는 문구는 세 번째 지점(서버 운영자)에 대한 약속일 뿐입니다. 앞의 두 지점은 원격 서버 운영자가 통제할 수 없습니다. 특히 대화 기록이 공유 링크 등으로 외부에 공유될 경우 키도 함께 노출됩니다. 지난 9월 조사에서 ChatGPT, Claude, Gemini, Grok의 공유 링크 30,990건을 별도의 보안 위협 표면으로 다루었던 이유가 여기에 있습니다.

※ 다만 세 곳에 기록된다는 점은 시스템 구조에 기반한 추론입니다. 실제 보존 기간과 범위는 클라이언트·서버 구현에 따라 달라질 수 있습니다. 이번 조사는 도구를 실행하지 않았으므로 로그 저장 여부까지 직접 검증하지는 않았습니다.

타사(제3자) 서비스 키를 요구하는 서버 15곳

확인된 3,705개 필드 대부분은 해당 서버가 직접 발급한 키를 요구합니다. 예를 들어 api.datronis.com은 자체 토큰(dtk_)을 요구하면서 "헤더 전송을 권장한다"고 안내합니다. bounty.brelsfordsoftware.com은 "비밀번호처럼 다루라"고 명시합니다. 이 경우 서버 운영자가 키의 발급자이므로 노출되더라도 피해 범위가 해당 서비스 내로 한정됩니다.

더 심각한 문제는 서버 운영자가 아닌 제3자 서비스의 자격증명을 요구하는 경우입니다. 필드 설명에 타사 서비스명이 명시된 51개 필드를 전수 검토했습니다. 웹훅 서명 시크릿, 공개 검증키, 서버 자체 토큰, 저장된 자격증명의 ID 등을 제외하니 총 15개 서버가 타사 서비스의 API 키를 직접 요구하고 있었습니다.

요구 자격증명 종류해당 서버 목록
GitHub 토큰shpbl.com, nittim.com, neblla.com, api.fadehost.com, handoff.lol
LLM 제공사 키 (OpenAI / Anthropic / Gemini)www.ia-qa.com, api.chieflab.io, pseo.quantumcx.net
Atlassian API 토큰www.ia-qa.com
Cloudflare API 토큰 / Turnstile secretapi.proof.holdings, api.furrowforms.com
Telegram / Discord 봇 토큰api.vendo-ai.com, api.proof.holdings, getsocialclaw.com, sendit.infiniteappsai.com
AWS S3 Access & Secret Keymcp.pandavideo.com
Etherscan API 키api.timzinin.com
shpbl.com의 write_to_repo 도구 스키마 원문 발췌. github_token 필드는 Contents와 Pull requests 쓰기 권한 토큰을 받으며 마스킹 지정(format, writeOnly)이 없음

대표적인 사례는 두 곳입니다. www.ia-qa.com은 152개의 도구를 제공하는 서버입니다. 이 중 post_jira_comment 도구는 Jira URL, 이메일, 그리고 Atlassian API 토큰을 필수 인자로 지정하고 있습니다. 권한 범위(Scope)가 제한되지 않은 Atlassian 토큰은 해당 계정의 권한을 그대로 보유합니다. 스키마에서 최소 권한을 요구하지 않기 때문에 강력한 권한을 가진 토큰이 대화창을 거쳐 제3자 서버로 전송될 위험이 있습니다.

api.proof.holdings는 DNS 설정 변경 권한을 포함하는 Cloudflare API 토큰을 필수 인자로 요구합니다.

GitHub 토큰을 요구하는 서버 5곳 중 4곳은 GitHub App 설치나 Fine-grained 토큰 사용과 같은 보안 대안을 함께 안내하고 있었습니다. 운영자들도 보안 위험을 인지하고 있다는 뜻입니다. 그럼에도 토큰 입력 필드가 유지되는 이유는 명확합니다. '앱 설치'보다 '토큰 복사 및 붙여넣기'가 사용자 입장에서 훨씬 간편하기 때문입니다.

사용자는 악성 서버를 구별할 수 없습니다

위에서 언급한 15개 서버가 악의적인 목적으로 운영된다고 단정할 수는 없습니다. 문제는 사용자 입장에서 정상 서버와 악성 서버를 구별할 수 있는 수단이 없다는 점입니다.

공식 레지스트리는 게시자의 네임스페이스 소유권만 검증합니다. io.github.<사용자명>은 GitHub 로그인으로, 자체 도메인은 DNS·HTTP 검증으로 확인합니다. 이 검증은 게시자가 이 이름의 소유자인지만 보증합니다. 서버가 전달받은 자격증명을 안전하게 처리하는지는 보증하지 않습니다.

레지스트리 등록 장벽 또한 낮습니다. 전체 서버의 64.6%(25,989개)가 io.github.* 네임스페이스로 등록되어 있습니다. GitHub 계정만 있으면 누구나 등록할 수 있는 경로입니다. 이렇게 등록한 계정은 12,603개였습니다. 하나의 계정이 2,365개의 서버를 등록한 사례도 있었습니다.

서버 이름 역시 신뢰 기준이 되지 못합니다. GitHub, Slack, Notion, Stripe, Jira 등 유명 서비스 19곳의 명칭이 포함된 서버는 314개였으나, 해당 기업의 공식 네임스페이스에서 게시된 서버는 4개에 불과했습니다. 예컨대 이름에 slack이 포함된 서버 18개는 모두 Slack이 아닌 제3자가 게시한 서버였습니다. 커뮤니티 제작 서버 자체는 생태계의 자연스러운 일부입니다. 다만 사용자가 이름만 보고 공식 여부를 판단하기는 어렵습니다.

결과적으로 정상 서버 위장은 어렵지 않습니다. 도구 이름과 설명을 공식 서비스와 비슷하게 작성한 뒤 토큰 필드 설명에 "이 호출에만 사용되며 저장하지 않음"이라고 기재하면 충분합니다. 스키마 구조만으로는 사용자도, LLM 모델도 진위 여부를 판별할 수 없습니다.

유사한 사건이 발생한 적이 있습니다. 2025년 9월, npm에 등록된 postmark-mcp 패키지는 Postmark 공식 라이브러리와 동일한 이름과 코드로 업로드되었습니다. 그러나 1.0.16 버전 업데이트에서 한 줄의 악성 코드가 추가되었습니다. 이후 해당 서버를 거치는 모든 이메일이 외부 주소로 숨은 참조(BCC) 처리되었습니다. 이 패키지는 삭제되기 전까지 1,643회 다운로드되었습니다(The Hacker News).

개선 방향

MCP 서버 개발자라면 자격증명은 도구 인자가 아닌 전송 계층(Transport Layer)에서 처리해야 합니다. MCP 명세가 지원하는 OAuth 흐름이나 HTTP 인증 헤더를 사용하면 키가 대화 맥락에 노출되지 않습니다. 불가피하게 인자로 수신해야 한다면, ship.page 사례처럼 writeOnly: true 또는 format: password 속성을 명시해 클라이언트가 해당 값을 마스킹할 수 있도록 해야 합니다. 또한 제3자 연동 시에는 GitHub App처럼 권한 범위를 최소화하고 철회가 쉬운 방식을 기본값으로 제공해야 합니다.

MCP를 활용하는 개발자라면 에이전트 대화창에 직접 입력한 API 키는 이미 여러 지점에 복사되었다고 가정하는 것이 안전합니다. 만료 기한이 짧고 권한이 최소화된 Fine-grained 토큰을 사용하십시오. 작업이 완료되면 해당 토큰을 폐기하거나 로테이션하십시오.

기업 보안팀이라면 AI 에이전트와의 대화 기록과 연동 파이프라인 전체를 자격증명 유출 표면(Attack Surface)으로 다루어야 합니다. 대화 맥락에 포함된 키는 Slack 스레드, Jira 티켓, Notion 문서, GitHub Issue 등으로 쉽게 전파됩니다.

Cremit Platform은 GitHub, GitLab, Bitbucket, Slack, Jira, Confluence, Notion, Google Drive, AWS S3 등 다양한 환경에서 1,000종 이상의 시크릿 유출을 탐지합니다. 탐지된 키의 유효성을 발급 서비스에 직접 확인합니다. 대화창 밖으로 유출된 자격증명이 어디에 잔존하는지 파악하는 것부터 시작할 수 있습니다.

조사의 한계 및 참고 사항

이 조사는 공식 레지스트리에 등록된 원격 서버만을 대상으로 진행했습니다. 레지스트리 외부에 독립적으로 존재하는 서버는 포함되지 않았으므로 실제 위험 규모는 더 클 수 있습니다.

또한 도구 이름, 설명, 입력 스키마만을 바탕으로 분석했습니다. 전달된 키가 서버에 저장되거나 오용되는지는 실제 호출로만 확인할 수 있습니다. 이번 조사에서는 도구 호출을 수행하지 않았습니다.

3,705개 자격증명 필드에는 서버 자체 키가 대부분 포함되어 있습니다. 제3자 키로 확정한 것은 설명란에 서비스명이 명확히 기재된 15곳입니다. 이름 없이 api_key로만 표기된 필드 중에도 타사 키가 포함되어 있을 가능성이 있습니다. 유명 서비스명을 단 서버 수는 이름 문자열 일치로 산정한 값이라 공식 게시자가 일부 누락되었을 수 있습니다.

마지막으로 이 글은 특정 서버의 취약점을 고발하기 위한 목적이 아닙니다. 언급된 모든 서버는 공개 레지스트리에 스스로 등록되어 있었습니다. 조사 과정에서는 MCP 표준 핸드셰이크와 읽기 전용 목록 조회 요청만을 사용했습니다.

네트워크에 공유해보세요LinkedInX

이 글이 유익하셨나요?

네트워크에 공유해보세요

Share:

이어서 읽기

뉴스레터

다음 글을 메일로 받아보세요

Cremit의 월간 자격증명 보안 브리프. 한 통에 핵심만 담습니다.

이메일을 판매하거나 외부에 넘기지 않으며, 언제든 수신거부할 수 있습니다.