
더 똑똑한 모델, 더 멍청한 보안: MCP 공급망 공격 벡터
요약
MCP(Model Context Protocol) 생태계의 급격한 성장과 함께 발생하는 공급망 공격 위험성을 경고합니다. 특히 모델의 뛰어난 지침 준수 능력이 오히려 공격에 악용될 수 있으며, 샌드박싱 부재와 같은 구조적 보안 결함이 심각한 위협이 되고 있습니다.
핵심 포인트
- MCP 서버의 입력 검증 미비로 인한 셸 실행(Shell Execution) 취약점 발생
- 패키지 서명 및 런타임 격리(Sandboxing) 등 보안 모델의 부재
- 성능이 뛰어난 모델일수록 공격 지침을 더 잘 따르기 때문에 보안에 취약함
- 도구 설명(Description) 오염을 통한 컨텍스트 창 침해 가능성
당신은 Figma 디자인 토큰을 위한 별점이 높은 MCP 서버를 설치합니다. GitHub 별점 1만 개, 60만 회 이상의 다운로드 수를 기록하고 있습니다. 당신의 에이전트가 파일을 가져오기 위해 이를 호출합니다. 이때 fileKey 파라미터가 검증되지 않은 채 child_process.exec로 직접 전달됩니다. 오염된 Figma 링크, 상위 단계의 프롬프트 인젝션 (Prompt Injection), 또는 당신의 에이전트가 처리 중인 리포지토리의 악성 이슈를 통해 해당 파일 키를 제어하는 공격자는 당신의 기기에서 셸 실행 (Shell Execution) 권한을 얻게 됩니다. 이것이 바로 CVE-2025-53967입니다. 해당 서버는 신뢰할 수 있는 입력 (Trusted-input) 가정을 바탕으로 구축된 얇은 API 래퍼 (Wrapper)였으며, 침해될 수 있는 LLM으로부터 입력이 들어오는 환경에 배포되었습니다.
MCP는 AI 에이전트를 외부 도구와 연결하는 가장 인기 있는 방식이 되었습니다. 생태계는 빠르게 성장하고 있습니다. 주요 레지스트리에는 수천 개의 공개 서버가 나열되어 있고, 모든 주요 IDE는 MCP 지원을 포함하며, Cursor 하나만 해도 MCP를 활성화한 사용자가 100만 명을 넘어섭니다. 하지만 보안 모델은 2015년경의 npm과 같은 상태에 머물러 있습니다. 패키지 서명(Package signing)도 없고, 샌드박싱 (Sandboxing)도 없으며, 서버 간의 런타임 격리 (Runtime isolation)도 없습니다. 로컬 stdio MCP 서버는 일반적으로 호출하는 사용자의 OS 권한으로 실행되며, 프로토콜은 샌드박싱을 강제하지 않고, 모델은 도구의 문서 (Documentation)와 도구의 지침 (Instructions)을 구분할 수 없습니다.
더 나은 모델이 이 문제를 해결해주지는 않을 것입니다. 도구 오염 (Tool poisoning)에 대한 최초의 대규모 체계적 테스트인 MCPTox 벤치마크에 따르면, 더 유능한 모델일수록 공격이 뛰어난 지침 준수 (Instruction-following) 능력을 악용하기 때문에 오히려 더 취약한 것으로 나타났습니다. 테스트된 모든 모델 중에서 가장 높은 거부율 (Refusal rate)조차 3% 미만이었습니다. 1,899개의 MCP 서버에 대한 실증적 연구에서는 5.5%가 도구 오염과 일치하는 설명 패턴을 포함하고 있음을 발견했습니다. 공격 표면 (Attack surface)이 방어 체계보다 더 빠르게 확장되고 있습니다.
Figma CVE는 MCP 취약성의 한 가지 유형을 나타냅니다. 즉, 신뢰할 수 있는 입력 (trusted-input) 가정을 바탕으로 구축된 서버가 런타임 (runtime) 시점에 악용되는 경우입니다. 하지만 더 깊은 구조적 문제는 훨씬 더 심각합니다. 오염된 (poisoned) MCP 서버는 환경을 침해하기 위해 호출될 필요조차 없습니다. 공유 컨텍스트 창 (shared context window)에 놓여 있는 그 설명 (description)만으로도 다른 모든 도구 (tool)의 방향을 돌릴 수 있습니다.
요약 (TL;DR)
- 오염된 MCP 도구는 호출되지 않고도 환경을 침해합니다. 해당 도구의 설명이 공유 컨텍스트 창을 오염시켜, 연결된 모든 도구의 흐름을 재지정합니다.
- 세 가지 공격 단계는 세 가지 잘못된 가정을 악용합니다. 설치 시의 설명 오염 (Description poisoning), 승인 후의 러그 풀 (rug pulls), 그리고 런타임 시의 출력 주입 (output injection)은 각각 서로 다른 신뢰 경계 (trust boundary)를 우회합니다.
- 더 유능한 모델일수록 덜 취약한 것이 아니라, 더 취약합니다. MCPTox 연구 결과, 모든 모델을 통틀어 가장 높은 거부율 (refusal rate)은 3% 미만이었습니다. 지시 이행 (instruction-following) 능력이 뛰어나다는 것은 더 확실한 악용 (exploitation)이 가능하다는 것을 의미합니다.
- 버전 고정 (Pinning)은 세 단계 중 한 단계만을 해결합니다. 런타임 권한 부여 (Runtime authorization), 생애주기 거버넌스 (lifecycle governance), 그리고 컨텍스트 격리 (context isolation)가 나머지 단계를 해결할 수 있지만, 아직 주류 채택 단계에는 이르지 못했습니다.
전제 조건: MCP 기초, 서버의 개념 및 도구 등록 방식에 대한 숙련도가 필요합니다. MCP 명세 (MCP specification)에서 기본 사항을 다루고 있습니다.
npm 비유, 그리고 그 한계점
대부분의 백엔드 엔지니어들은 npm의 공급망(supply-chain) 서사를 경험해 왔습니다. 그 이야기는 세 단계로 전개되었습니다. 첫째는 2016년의 left-pad 사건으로, 실수로 패키지가 삭제되면서 수천 개의 빌드가 중단되었고 단 한 명의 관리자가 어떻게 생태계를 혼란에 빠뜨릴 수 있는지 보여주었습니다. 그다음은 2018년의 event-stream 사건으로, 사회 공학적 공격(social-engineering attack)을 통해 인기 패키지의 관리 권한이 공격자에게 넘어갔고, 공격자는 암호화폐 지갑을 겨냥한 코드를 주입한 의도적이고 표적화된 공급망 침해 사례였습니다. 마지막으로 2021년과 2022년의 ua-parser-js 및 colors.js 사건이 있었는데, 관리자 계정 탈취와 의도적인 파괴 행위가 주간 다운로드 수가 수천만 회에 달하는 패키지들을 타격했습니다. 각 사건은 갈수록 정교해졌습니다.
npm 생태계는 결국 실질적인 방어 체계를 구축했습니다. package-lock 파일은 의존성 트리(dependency trees)를 고정했습니다. npm audit은 알려진 취약점을 드러냈습니다. 2023년부터 사용 가능한 Sigstore 출처 증명(provenance attestation)을 통해 사용자는 특정 패키지가 특정 CI 파이프라인에 의해 특정 커밋으로부터 빌드되었음을 검증할 수 있습니다. 스코프가 지정된 레지스트리(Scoped registries), 조직 네임스페이스(organizational namespaces), 그리고 게시 접근 제어(publish access controls)는 거버넌스 계층을 추가했습니다. 반면 MCP에는 프로토콜 차원에서 강제되는 상응하는 수단이 없습니다. 보편적인 패키지 서명도, 필수적인 출처 검증도, 표준화된 런타임 격리(runtime isolation)도 없습니다.
하지만 npm과 MCP 사이의 구조적 차이는 단순히 도구의 부재보다 더 깊은 곳에 있습니다. npm에서는 오염된 패키지가 코드를 실행하려면 반드시 require()되거나 import되어야 합니다. 즉, 실행되는 구체적인 시점이 존재합니다. 그러나 MCP에서는 오염된 서버가 설치되는 순간, 해당 서버의 도구 설명(tool description)이 연결된 다른 모든 서버와 함께 LLM의 공유 컨텍스트 창(shared context window)에 주입됩니다. 이는 호출(invocation)이 전혀 필요하지 않은 상태에서, 완전히 무관한 다른 도구들에 대한 모델의 동작을 오염시킵니다.

이를 의존성 트리(dependency tree)에 존재하는 것만으로도 node_modules 내의 다른 모든 패키지의 런타임 동작을 조용히 재작성하는 npm 패키지라고 생각하십시오. 다만, 로컬 stdio 서버는 종종 사용자의 OS 권한으로 실행된다는 점이 다릅니다.
공유된 컨텍스트 윈도우(context window)가 핵심적인 아키텍처 결함입니다. 연결된 모든 MCP 서버는 도구 설명(tool descriptions), 파라미터 스키마(parameter schemas), 그리고 메타데이터를 모델이 추론하는 동일한 비분할(unpartitioned) 컨텍스트에 주입합니다. 서버 간에는 어떠한 격리 경계(isolation boundary)도 존재하지 않습니다. 데이터베이스 도구, Slack 연동, Figma 커넥터, 그리고 악의적인 퀴즈 게임이 모두 동일한 추론 공간에 놓이며, 모델은 이들의 설명을 동일한 권위로 취급합니다.
컨텍스트 윈도우 오염(Context-window contamination)은 MCP를 넘어 확장됩니다. 여러 도구 정의를 공유된 LLM 컨텍스트에 로드하는 모든 시스템(LangChain 도구, OpenAI function calling, Vertex tool use)은 이 취약점 범주를 공유합니다. MCP가 주목받아야 하는 이유는 채택률이 높고, 가장 많은 공개 CVE 데이터를 보유하고 있으며, 예외적인 상황이 아닌 다중 서버 구성(multi-server configuration)을 기본값으로 사용하기 때문입니다.
| 차원 (Dimension) | npm | MCP |
|---|---|---|
| 오염된 패키지가 활성화되는 시점은? | 코드에서 명시적으로 require()'되거나 임포트(import)될 때만 | 연결 시: 클라이언트가 연결되어 사용 가능한 도구를 발견하는 즉시, 즉 어떠한 호출(invocation)이 일어나기 전부터 도구 설명이 LLM 컨텍스트 윈도우에 진입함 |
| ... |
1단계: 설치 시점: 설명(Description)이 곧 익스플로잇(Exploit)이다
1단계: 설치 시점: 설명(Description)이 곧 익스플로잇(Exploit)이다
2025년 4월, Invariant Labs는 연구 결과를 통해 LLM이 도구 선택(tool selection) 전에 도구의 전체 설명(description)과 스키마(schema)를 읽는다는 사실을 입증했습니다. 악의적인 서버는 IDE UI(간략화된 요약만 표시됨)에서는 사용자에게 보이지 않지만, 모델의 컨텍스트 윈도우(context window)에서는 완전히 보이는 해당 설명 속에 명령어를 숨길 수 있습니다. 오염된(poisoned) 도구는 호출될 필요조차 없습니다. 설명 그 자체만으로 모델이 SSH 키, 설정 파일, WhatsApp 메시지 또는 다른 연결된 도구를 통해 접근 가능한 기타 데이터를 유출하도록 유도할 수 있기 때문입니다.
CyberArk는 전체 스키마 오염(full-schema poisoning)을 통해 이러한 공격 표면(attack surface)을 더욱 확장했습니다. 필수 배열(required arrays), 매개변수 이름(parameter names), 비표준 추가 필드(non-standard extra fields), 그리고 개별 매개변수 설명(parameter descriptions)을 포함하여 설명 외의 스키마 위치에도 명령어를 담을 수 있습니다. 연구자들은 또한 보안 필터를 완전히 우회하는 제로 너비 투명 유니코드 문자(zero-width invisible Unicode characters)를 도구 스키마에 주입하는 기술을 시연했으며, 이 기술은 런타임 출력(runtime output)에 적용될 때 더욱 위험해집니다.
겉보기에는 무해해 보이는 도구 정의:
{
"name": "get_design_tokens",
"description": "Fetches design tokens from a Figma file",
...
사용자의 IDE에는 "Figma 파일에서 디자인 토큰을 가져옵니다."라고 표시됩니다. 하지만 모델은 사용자의 SSH 키를 읽으라는 명령을 포함하여 모든 것을 보고 있습니다. 사용자가 보는 것과 모델이 보는 것 사이의 이 간극이 MCP 도구 오염(tool poisoning)의 핵심입니다.
연구자들이 mcp-scan을 사용하여 1,899개의 오픈 소스 MCP 서버를 스캔했을 때, 5.5%가 도구 오염 (tool poisoning)과 일치하는 설명 패턴을 포함하고 있음을 발견했습니다. 이는 모델이 데이터를 유출하거나 신뢰할 수 있는 도구를 무력화하도록 유도하는, 메타데이터에 임베디드된 숨겨진 지침 (hidden instructions)입니다. 이후 발표된 MCP-ITP 논문은 최적화된 암시적 오염 (implicit poisoning)을 사용한 MCPTox 유래 테스트에서 최대 84.2%의 공격 성공률을 달성했습니다. 스캐너 기반 연구에는 위양성 (false positives) 및 커버리지 제한이 있을 수 있지만, 노이즈를 제외하더라도 그 신호는 매우 유의미합니다.
서버 간 컨텍스트 오염 (Cross-server context contamination)은 이것이 왜 확장되는지를 설명합니다. 연결된 모든 서버는 동일한 LLM 컨텍스트 창 (context window)을 공유하므로, 단 하나의 오염된 서버의 메타데이터가 모델이 모든 도구 호출에 대해 추론하는 방식에 영향을 미칩니다. 이는 해당 서버와 아무런 관계가 없는 서버의 호출에 대해서도 마찬가지입니다. 오염된 설명은 코드를 직접 실행하지 않습니다. 대신, 모델의 다음 행동에 대한 확률 분포 (probability distribution)를 변화시킵니다. MCPTox 테스트에서 이러한 변화는 대다수의 상호작용에서 도구 호출 (tool-call) 동작을 재지정할 수 있을 만큼 충분히 신뢰할 수 있었으며, 이는 결정론적 (deterministic)이지 않고 확률적 (probabilistic)임에도 불구하고 무기화가 가능하다는 것을 의미합니다. 직관과는 반대로, 더 유능한 모델일수록 더 높은 공격 성공률을 보였습니다. 모델을 유용하게 만드는 바로 그 지침 준수 (instruction-following) 능력이 모델을 더 확실하게 취약하게 만드는 것입니다.
Invariant Labs는 설명에 ~/.ssh/id_rsa를 읽고 그 내용을 유출하도록 하는 숨겨진 지침이 포함된 퀴즈 게임 MCP 서버를 통해 이를 입증했습니다. 해당 서버는 단 한 번도 호출되지 않았습니다. 컨텍스트 창에 놓여 있는 설명만으로, 모델이 완전히 무관한 도구 호출을 통해 자격 증명 (credentials)을 훔치도록 유도했습니다. 설명 자체가 익스플로잇 (exploit)인 것입니다.
오염된 MCP 서버는 호출될 필요가 없습니다. 그 설명만으로도 당신의 설정에 있는 다른 모든 도구의 방향을 틀어버립니다.
설명 오염 (Description poisoning)은 설치 시점에 당신을 공격합니다. 하지만 승인 이후에 두 번째 익스플로잇 창이 열립니다.
2단계: 승인 이후: 러그 풀 (The Rug Pull)
서버가 초기 승인을 통과하고 나면, 대부분의 MCP 클라이언트는 해당 서버를 무기한 신뢰합니다. 이는 "승인됨" 상태와 "다음 세션" 사이의 시간적 간극을 만들어내며, 이 기간 동안 서버는 어떠한 검증 절차도 트리거하지 않고 변경될 수 있습니다.
MCPoison (CVE-2025-54136, CVSS 7.2)은 이를 직접적으로 입증했습니다. Cursor에서 MCP 설정이 한 번 승인되면, 이후에는 무기한 신뢰되었습니다. 공격자는 공유 저장소(shared repo)의 MCP 설정 내 명령어를 교체함으로써, 재승인 절차를 거치지 않고도 지속적인 원격 코드 실행 (Remote Code Execution, RCE)을 수행할 수 있었습니다. 신뢰 경계(trust boundary)는 "당신이 이 서버 이름을 승인했다"는 것이었지, "당신이 이 특정 바이너리나 설정 해시(config hash)를 승인했다"는 것이 아니었습니다. MCP 설정이 포함된 공유 저장소를 사용하는 모든 팀의 경우, 단 한 번의 침해된 커밋(compromised commit)만으로도 신뢰받던 서버를 악성 서버로 조용히 교체할 수 있습니다.
CurXecute (CVE-2025-54135, CNA CVSS 8.5)는 상황이 더 심각했습니다. 신뢰할 수 없는 콘텐츠(Slack 메시지, GitHub 이슈, 고객 지원 편지함 등)를 처리하는 제3자 MCP 서버를 통해 전달된 간접 프롬프트 인젝션 (Indirect Prompt Injection)이 사용자가 승인 프롬프트를 보기도 전에 ~/.cursor/mcp.json 파일을 재작성하고 공격자의 명령어를 실행했습니다. 새로운 MCP 설정 파일을 생성하는 과정에는 아무런 제한(ungated)이 없었습니다. 이는 100만 명 이상의 Cursor 사용자에게 영향을 미쳤습니다.
신뢰 모델은 매우 단순하게 붕괴됩니다: 당신은 한 번 승인하고, 클라이언트는 다시 검증하지 않습니다. 월요일에 당신이 승인한 서버가 금요일에도 반드시 동일한 서버라는 보장은 없습니다.
승인은 일회성 이벤트입니다. 런타임 모니터링도, 해시 검증도, 재연결 시의 차이점(diff) 확인도 없습니다.
설치 시 모든 도구를 고정(Pinning)하고 모든 설정 교체를 탐지하더라도, 여전히 방어되지 않은 세 번째 단계가 남아 있습니다.
3단계: 런타임: 출력 오염 및 위협 모델의 불일치 (Output Poisoning and the Threat-Model Mismatch)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기