보안 위험을 방지하기 위한 MCP 서버 감사 방법
요약
MCP 서버의 보안 취약점을 점검하기 위한 오픈 소스 도구인 mcp-security-scan을 소개합니다. 이 도구는 정적 분석을 통해 자격 증명 탈취, 데이터 유출, 안전하지 않은 실행 패턴 등을 탐색하고 신뢰 점수를 제공합니다.
핵심 포인트
- mcp-security-scan은 MCP 서버의 보안 위험을 점검하는 CLI 및 GitHub Action입니다.
- 자격 증명 탈취, 데이터 유출, 안전하지 않은 실행 등 6가지 범주의 위험을 탐색합니다.
- TypeScript, Python, JavaScript 소스 코드에 대해 정적 분석을 수행합니다.
- 0-100 사이의 신뢰 점수를 통해 서버의 보안 상태를 직관적으로 보여줍니다.
요약 (TL;DR): MCP 서버는 파일 시스템, 환경 변수 및 네트워크에 대해 놀라울 정도로 넓은 접근 권한을 가지고 실행됩니다. 하지만 대부분의 개발자는 보안 검토 없이 이를 배포합니다. mcp-security-scan은 자격 증명 탈취, 데이터 유출 및 안전하지 않은 실행 패턴을 점검하고 0-100 사이의 신뢰 점수를 출력하는 오픈 소스 CLI 및 GitHub Action입니다. 이 도구는 무료이며 MIT 라이선스를 따르고, 실행하는 데 약 30초 정도 소요됩니다.
만약 Claude나 다른 에이전트 런타임(agent runtime)에 MCP 서버를 연결했다면, 해당 서버가 실제로 무엇을 할 수 있는지에 대해 깊이 고민해보지 않았을 가능성이 높습니다. 이는 정상적인 일입니다. 당신은 도구 호출(tool calls)이 제대로 작동하게 만드는 데 집중하고 있었을 테니까요.
하지만 MCP 서버는 권한이 부여된 위치에서 실행됩니다. 서버는 에이전트와 외부 세계 사이에 위치하며, 파일을 읽고, 네트워크 요청을 보내고, 하위 프로세스(subprocesses)를 생성하며, 환경 변수에 접근할 수 있습니다. Model Context Protocol 명세는 보안 모델을 정의하는 것이 아니라, 통신 프로토콜(communication protocol)을 정의합니다. 서버 내부에서 어떤 일이 일어나는지는 전적으로 당신에게 달려 있습니다.
그 간극을 메워주는 것이 바로 mcp-security-scan입니다.
스캐너가 실제로 점검하는 항목
이 도구는 MCP 서버 소스 코드(TypeScript, Python, JavaScript 지원)에 대해 정적 분석(static analysis)을 수행하며, 다음 여섯 가지 범주의 위험을 탐색합니다:
자격 증명 탈취 패턴 (Credential theft patterns) — *_KEY, *_SECRET, *_TOKEN, *_PASSWORD 또는 *_CREDENTIAL과 일치하는 항목을 건드리는 환경 변수 읽기 작업입니다. 이 모든 것이 버그인 것은 아니지만, 반드시 인지하고 있어야 합니다. 만약 당신의 날씨 도구가 STRIPE_SECRET_KEY를 읽고 있다면, 이는 알아둘 가치가 있는 문제입니다.
데이터 유출 (Data exfiltration) — 도구 핸들러(tool handlers) 내부에서 발생하는 외부 HTTP 호출입니다. 이 역시 본질적으로 나쁜 것은 아닙니다. 하지만 단순히 문자열을 포맷팅하기로 되어 있는 도구가 외부 엔드포인트로 POST 요청을 보내서는 안 됩니다.
안전하지 않은 실행 (Unsafe execution) — exec(), eval(), subprocess.run(), child_process.spawn() 및 이와 유사한 함수들입니다. 이러한 것들은 보안 전문가들을 밤잠 설치게 만드는 요소들입니다. 사용자 제공 입력을 eval 하는 MCP 도구는 원격 코드 실행(remote code execution) 사고가 발생하기를 기다리는 것과 같습니다.
파일 시스템 접근 (Filesystem access) — 작업 디렉토리 외부의 파일을 읽거나 씁니다. 특히 에이전트가 사용자 입력에서 유래한 파일 경로를 전달할 때 매우 위험합니다.
코드 난독화 (Code obfuscation) — 높은 엔트로피(high-entropy)를 가진 문자열, base64로 인코딩된 페이로드, 소스 맵(source maps) 없이 배포되는 축소된(minified) 코드 등이 해당됩니다. 이것들이 자동으로 악성이라는 뜻은 아니지만, 하나의 신호(signal)가 됩니다.
의존성 혼동 위험 (Dependency confusion risks) — 인기 있는 패키지를 모방하는 패키지 이름이나, 일반적이지 않은 레지스트리에서 가져온 의존성 등이 포함됩니다.
실행 방법
npx @agentgraph/mcp-security-scan ./my-mcp-server
또는 전역(globally)으로 설치하여 사용하세요:
npm install -g @agentgraph/mcp-security-scan
mcp-security-scan ./my-mcp-server
Python 프로젝트도 동일한 방식으로 작동합니다. 스캐너가 package.json 또는 pyproject.toml을 통해 런타임(runtime)을 감지합니다.
출력 결과는 다음과 같습니다:
AgentGraph MCP Security Scanner v0.4.1
Scanning: ./my-mcp-server
...
신뢰 점수(trust score)는 AgentGraph의 신뢰 배지(trust badge) 시스템과 직접 통합됩니다. 따라서 다른 사람들이 사용할 MCP 서버를 게시하는 경우, README에 검증된 점수를 첨부할 수 있습니다.
GitHub Action
.github/workflows/security.yml 파일에 다음 내용을 추가하세요:
name: MCP Security Scan
on:
...
fail-below 임계값(threshold)은 설정 가능합니다. 대부분의 프로젝트에 대해 기본값은 70으로 설정되어 있습니다. 이 점수 미만이라면, 해결되지 않은 최소 하나 이상의 HIGH(높음) 등급 또는 여러 개의 MEDIUM(중간) 등급 취약점이 존재한다는 의미입니다. SARIF 출력 형식을 지원하므로, 결과가 GitHub의 Security 탭에 네이티브하게 표시됩니다. 이는 이미 CodeQL이나 유사한 도구를 사용 중인 경우 매우 유용합니다.
아키텍처 결정 (그리고 우리가 실수했던 부분)
MCP 서버처럼 정의가 느슨한 대상을 위한 보안 스캐너를 구축하는 과정에는 솔직하게 밝힐 만한 몇 가지 선택 사항들이 있었습니다.
정적 분석 (Static analysis) vs. 동적 분석 (Dynamic analysis). 우리는 정적 분석을 선택했습니다. 동적 분석을 사용하면 서버를 실제로 실행하고 그 동작을 관찰할 수 있으므로 더 많은 것을 잡아낼 수 있었을 것입니다. 하지만 이를 안전하게 수행하는 것은 훨씬 더 어렵습니다. MCP 서버의 임의 코드를 샌드박스 (Sandbox)에서 실행하여 동작을 관찰하는 작업은 실제 인프라가 필요한 영역입니다. 정적 분석은 난독화된 런타임 (Runtime) 동작을 놓칠 수 있지만, 빠르고 안전하며 별도의 설정 없이 CI (지속적 통합) 환경에서 작동합니다.
트레이드오프 (Trade-off): 충분한 동기를 가진 악의적인 공격자는 정적 분석을 회피할 수 있습니다. 누군가 정말로 악성 동작을 숨기려 한다면, 패턴 매칭 (Pattern-matching)이 잡아낼 수 없는 방식으로 이를 인코딩할 것입니다. 우리는 이 사실을 알고 있습니다. 스캐너는 보증 수표가 아닙니다. 이는 명백한 것들을 잡아내고, 명백히 위험한 것을 배포하는 데 드는 비용을 높여주는 기준점 (Baseline)입니다.
정규 표현식 (Regex) vs. AST 파싱 (AST parsing). 첫 번째 버전에서는 Python의 경우 정규 표현식 패턴을 사용했고, TypeScript/JavaScript의 경우 가벼운 AST 워크 (AST walk)를 사용했습니다. 정규 표현식은 빠르고 유지보수가 쉽지만, 오탐 (False positives)을 발생시킵니다. # don't use eval()이라고 적힌 주석조차 eval 체크를 트리거하게 됩니다. 우리는 v0.5에서 Python 분석기를 ast 모듈 파싱을 사용하도록 마이그레이션할 예정이며, 이를 통해 오탐을 크게 줄일 수 있을 것입니다.
이것이 보안 도구의 특징입니다. 오탐은 도구 자체에 대한 신뢰를 떨어뜨립니다. 개발자들이 경고를 무시하는 법을 배우게 되면, 스캐너는 소음 (Noise)이 되어버립니다. 우리는 포괄적이지만 시끄러운 결과물보다는, 개수는 적더라도 신뢰도가 높은 탐지 결과를 제공하는 쪽을 택하겠습니다.
신뢰 점수 산출 방식 (Trust score math). 0-100 점수는 가중 합계입니다. HIGH 탐지 항목은 각각 25점(최대 2개까지), MEDIUM 탐지 항목은 각각 10점(최대 3개까지), LOW 탐지 항목은 각각 3점이 차감됩니다. 100점에서 시작하여 0점까지 내려갈 수 있지만 음수로 내려가지는 않습니다. 이것은... 괜찮습니다. 정교한 리스크 모델 (Risk model)은 아닙니다. 하지만 우리가 테스트한 사례들에 대해 직관적으로 맞는 수치를 만들어내며, 개발자들이 왜 자신의 점수가 그와 같은지 이해할 수 있을 만큼 충분히 투명합니다.
우리는 악용 가능성 (exploitability)과 영향력 (impact) 차원을 포함하는 CVSS 스타일의 점수 산정 방식과 같은 더 정교한 모델을 고려했습니다. 하지만 v1 버전에서는 정적 분석 (static analysis)의 신호 품질(signal quality)에 비해 그 복잡성이 정당화되지 않는다고 판단하여 채택하지 않기로 했습니다. AST 패턴 매칭 (AST pattern matching)을 수행할 때는 해당 eval() 호출이 도구 핸들러 (tool handler)로부터 도달 가능한지, 아니면 데드 코드 (dead code) 속에 묻혀 있는지 실제로 알 수 없기 때문입니다. CVSS 수준의 정밀도를 갖춘 것처럼 가장하는 것은 오해를 불러일으킬 수 있습니다.
MCP 보안이 보기보다 복잡한 이유
올해 초 발생한 Moltbook 침해 사고로 인해 150만 개의 API 토큰이 노출되었습니다. 해당 사고는 MCP 전용 공격은 아니었지만, 공격 표면 (attack surface)은 유사합니다. 즉, 에이전트 도구와 자격 증명 (credentials)을 통합하면서도 해당 도구들이 실제로 무엇을 하는지에 대한 검증이 불충분한 플랫폼이라는 점입니다.
OpenClaw의 기술 마켓플레이스는 지난 공개 감사에서 제출물의 12%가 멀웨어 (malware)로 분류되었습니다. 이는 단순한 반올림 오차가 아닙니다. 도구 8개 중 1개가 해서는 안 될 행동을 하고 있다는 뜻입니다.
문제는 MCP 서버를 작성하기가 쉽고, 이를 게시하는 것도 점점 더 쉬워지고 있다는 점입니다. "내가 무언가를 만들었다"와 "다른 사람의 에이전트가 내 것을 실행한다" 사이의 마찰이 매우 낮습니다. 이는 생태계 성장에는 좋지만, 보안에는 좋지 않습니다.
이번 주 HN(Hacker News)에 출시된 Traceforce(AI 앱을 위한 전사적 보안 모니터링)도 기업 측면에서 동일한 문제에 직면해 있습니다. 그들은 AI 앱이 런타임 (runtime)에 무엇을 하는지 감시합니다. 우리는 배포 전 (before deployment)에 문제를 잡아냅니다. 두 접근 방식 모두 필요합니다. "이 에이전트가 주장하는 대로 행동하고 있는가"라는 질문은 단일 계층에서 단 하나의 정답으로 해결될 수 없기 때문입니다.
커스텀 통합을 위한 API 사용
스캐너를 표준 CI 파이프라인 (CI pipeline) 이외의 환경에 통합하고 싶다면, 다음과 같은 REST API를 사용할 수 있습니다:
import { MCPSecurityScanner } from '@agentgraph/mcp-security-scan';
const scanner = new MCPSecurityScanner({
...
API 키는 결과를 AgentGraph 신뢰 레지스트리(trust registry)에 게시하고 README에 검증된 배지(verified badge)를 받고자 하는 경우에만 필요합니다. 스캔 자체는 완전히 로컬(local)에서 수행됩니다. API 키가 설정되어 있지 않으면 아무것도 사용자의 기기를 떠나지 않습니다.
스캐너가 감지하지 못하는 것들
한계점에 대해 솔직하게 말씀드리자면 다음과 같습니다:
런타임 동작 (Runtime behavior). 만약 서버가 소스 코드에 없는 URL로부터 런타임(runtime) 중에 악성 플러그인을 로드한다면, 정적 분석(static analysis)은 이를 포착할 수 없습니다. 이는 알려진 공백입니다.
로직 버그 (Logic bugs). 스캐너는 귀하의 도구가 무엇을 수행하도록 설계되었는지 이해하지 못합니다. 만약 도구가 파일을 읽도록 설계되었고 실제로 파일을 읽는다면, 설령 읽는 특정 파일이 민감한 정보일지라도 이는 'FAIL'이 아닌 'WARN'으로 분류됩니다. 해당 동작이 적절한지 평가하려면 사람이 직접 확인해야 합니다.
의존성에서의 공급망 공격 (Supply chain attacks in dependencies). 저희는 명백한 혼동 공격(confusion attacks)을 방지하기 위해 패키지 이름을 확인하지만, 의존성 트리(dependency tree) 전체에 대한 완전한 감사를 수행하지는 않습니다. 이를 위해서는 npm audit 또는 pip-audit를 사용하십시오. 해당 작업에는 그것들이 더 나은 도구입니다.
난독화된 악의적 코드 (Obfuscated malice). 페이로드(payload)를 base64 설정 문자열처럼 보이도록 인코딩하는 결연한 공격자는 아마도 통과할 수 있을 것입니다. 저희는 엔트로피(entropy)가 높은 문자열을 플래그(flag)로 표시하지만, 해당 검사의 오탐률(false positive rate)이 충분히 높기 때문에 많은 프로젝트에서 이 설정을 낮추어 조정하곤 합니다.
스캐너는 천장이 아니라 바닥입니다. 스캐너는 아예 있어서는 안 될 것들, 즉 eval() 호출, 자격 증명이 필요 없는 도구에서의 자격 증명(credential) 읽기, README에 명시되지 않은 외부 HTTP 호출 등을 잡아냅니다.
MCP 서버를 위한 신뢰 배지 받기
npm, PyPI 또는 다른 곳에 MCP 서버를 게시하는 경우, 스캐너를 실행하고 점수를 게시하는 데 약 2분 정도 소요됩니다:
mcp-security-scan . --publish --api-key $AGENTGRAPH_API_KEY
README에 다음과 같은 배지를 받을 수 있습니다:
[](https://agentgraph.co/server/your-server-id)
해당 배지는 무엇이 스캔되었는지, 어떤 버전인지, 그리고 발견된 결과(findings)가 무엇인지를 보여주는 공개 감사(audit) 페이지로 연결됩니다. GitHub Action을 통해 새로운 코드를 푸시하면 자동으로 업데이트됩니다.
이 부분은 더 넓은 범위의 AgentGraph 프로젝트와 연결되는 지점입니다. 스캐너 자체로도 독립적으로 유용하지만, 신뢰 배지(trust badge)야말로 누군가가 자신의 데이터를 대상으로 귀하의 MCP 서버를 실행할지 여부를 결정할 때 그 점수를 의미 있게 만드는 요소입니다.
저장소(repo)는 github.com/agentgraph-co/mcp-security-scan에 있으며, MIT 라이선스로 제공되고 PR(Pull Request)이 열려 있습니다. 저희는 특히 Python AST 분석기(analyzer) 및 추가적인 점검 카테고리와 관련된 기여에 관심이 많습니다.
DID, 신뢰 점수(trust scoring), 에이전트 신원(agent identity) 등 더 넓은 신뢰 인프라(trust infrastructure) 맥락에 대해서는 agentgraph.co에서 확인하실 수 있습니다. 스캐너는 그 중 하나의 구성 요소입니다. 저희의 목표는 어떤 에이전트나 MCP 서버를 보더라도 "이것을 믿어도 되는가"라는 질문에 실질적인 답을 얻을 수 있는 세상을 만드는 것입니다.
현재 그 질문에 대한 답변은 대개 "잘 모르겠지만, README는 괜찮아 보였어요"입니다. 이것으로는 충분하지 않습니다.
이 포스트는 AI의 도움을 받아 생성되었으며 AgentGraph 팀의 검토를 거쳤습니다. 저희는 이 점에 대해 투명성을 유지하기 위해 노력하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기