티스토리 뷰

📌 3줄 요약

1. 공개 저장소에 올라온 악성 이슈 하나가 AI 에이전트를 조종해, 같은 계정의 비공개 저장소 정보를 공개 PR로 흘려보낸 사례입니다 (Invariant Labs, 2025.05.26).

2. MCP 서버 코드의 버그가 아니라 "비공개 데이터 + 외부 입력 + 외부로 쓰기"가 한 에이전트에 모인 구조 문제라, 패치 한 번으로 끝나지 않습니다.

3. 지금은 Lockdown 모드·콘텐츠 정화가 생겼지만 "인가 경계가 아니다"라고 공식 문서가 밝히고 있어, 토큰 범위 축소와 읽기 전용 설정이 여전히 핵심입니다.


🎯 결론부터

GitHub MCP를 쓰는 AI 에이전트가 공개 저장소의 글을 읽을 수 있고, 비공개 저장소에도 접근할 수 있고, 공개 저장소에 글을 쓸 수 있다면 같은 유형의 유출이 언제든 다시 일어날 수 있습니다.

해결의 방향은 단순합니다. 이 세 가지 중 적어도 하나는 한 세션 안에서 끊어 두는 것입니다. 이 글은 사건 흐름 → 왜 막기 어려운지 → 1년여가 지난 지금(2026년 10월) 무엇이 바뀌었는지 → 실제로 켜야 할 설정 순서로 정리합니다.


🧭 무슨 일이 있었나

MCP(Model Context Protocol)는 AI 에이전트가 외부 도구·서비스를 호출할 수 있게 해 주는 표준입니다. GitHub는 공식 MCP 서버(github/github-mcp-server)를 제공하고, 이를 연결하면 에이전트가 이슈 조회, 파일 읽기, PR 생성 같은 작업을 대신 수행합니다.

 

2025년 5월 26일, AI 보안 연구 기업 Invariant Labs는 이 공식 서버를 연결한 에이전트가 악성 GitHub 이슈 하나로 조종되어 비공개 저장소 데이터를 유출할 수 있음을 공개했습니다. 이들은 이런 공격 흐름을 Toxic Agent Flow라고 불렀습니다.

항목 내용
공개일 2025년 5월 26일
발견 Invariant Labs (2025년 6월 Snyk에 인수)
대상 GitHub 공식 MCP 서버를 연결한 모든 에이전트 (특정 모델·클라이언트에 한정되지 않음)
시연 환경 Claude Desktop + Claude 4 Opus
공격 유형 간접 프롬프트 인젝션 (외부 콘텐츠에 숨긴 지시를 에이전트가 따르게 함)
결과 비공개 저장소 목록·내용 등 개인 정보가 공개 저장소 PR에 기록됨
성격 서버 코드 결함이 아닌 에이전트 시스템 구조 문제 (연구진 판단)

🔍 공격은 이렇게 흘러갔다

전제는 평범합니다. 한 사용자가 누구나 이슈를 쓸 수 있는 공개 저장소와, 개인 자료가 담긴 비공개 저장소를 함께 갖고 있고, 에이전트에는 이 계정 권한으로 GitHub MCP가 연결되어 있습니다.

단계 무슨 일이 일어나나
① 심기 공격자가 공개 저장소에 에이전트를 겨냥한 지시문이 담긴 이슈를 작성 (GitHub 규칙상 누구나 가능)
② 요청 사용자가 "공개 저장소의 열린 이슈를 확인해 줘" 같은 평범한 요청을 함
③ 주입 에이전트가 이슈 목록을 읽다가 악성 이슈의 지시를 사용자 요청처럼 받아들임
④ 조회 에이전트가 같은 토큰으로 비공개 저장소 정보를 컨텍스트로 불러옴
⑤ 유출 불러온 정보를 공개 저장소의 새 PR에 기록
⑥ 회수 공개 PR이므로 공격자를 포함해 누구나 열람

시연에서 유출된 것은 데모 계정의 비공개 프로젝트 정보, 이주 계획, 급여 같은 개인 정보였습니다. 공격자는 사용자의 PC나 토큰에 직접 손대지 않았고, 공개 이슈 하나만 썼다는 점이 핵심입니다.

⚠️ 승인 창이 있어도 안심할 수 없는 이유

Claude Desktop은 기본적으로 도구 호출마다 사용자 확인을 요구합니다. 하지만 연구진은 많은 사용자가 "항상 허용(Always Allow)"을 선택하고 개별 동작을 더 이상 지켜보지 않는다고 지적했습니다. 승인 절차는 켜져 있을 때만 방어선입니다.


🔐 왜 패치로 끝나지 않나 — 치명적 3요소

Invariant Labs는 이 문제가 GitHub MCP 서버 코드의 결함이 아니라 에이전트 시스템 수준의 구조 문제이며, GitHub가 서버 쪽 패치만으로 해결할 수 없다고 밝혔습니다. 도구 자체가 오염된 것도 아니고, 완전히 신뢰할 수 있는 도구만으로도 발생한다는 점이 이전의 "도구 포이즈닝"과 다릅니다.

 

'프롬프트 인젝션'이라는 용어를 만든 Simon Willison은 2025년 6월 16일 이를 치명적 3요소(lethal trifecta)로 정리했습니다. 아래 세 능력이 한 에이전트에 모이면 공격자가 손쉽게 데이터를 빼낼 수 있다는 것이고, 그는 GitHub MCP 사례를 세 가지가 한 도구 안에 모두 들어 있는 예로 들었습니다.

요소 의미 이번 사례에서
비공개 데이터 사용자만 볼 수 있는 정보에 접근 비공개 저장소 읽기
외부 입력 공격자가 통제할 수 있는 글·이미지가 모델에 들어감 공개 저장소 이슈 읽기
외부 전송 데이터를 바깥으로 내보낼 통로 공개 저장소에 PR 생성

근본 원인은 LLM이 "누가 한 지시인지"를 확실히 구분하지 못한다는 데 있습니다. 사용자 요청이든 이슈 본문이든 결국 같은 텍스트로 모델에 들어가기 때문입니다. 연구진도 최신 정렬 모델을 사용했지만 비교적 단순한 주입에 넘어갔고, 기성 프롬프트 인젝션 탐지기 상당수도 이 공격을 잡지 못했다고 밝혔습니다. 그래서 모델의 안전성만 믿지 말고 시스템 설계로 막아야 한다는 결론이 나옵니다.


🕒 그 후 1년, 무엇이 바뀌었나

구조 문제라 "패치 완료"는 없지만, GitHub는 서버에 방어 기능을 계속 추가해 왔습니다. 2026년 10월 기준으로 확인한 주요 변화입니다.

시점 변화
2025.05.26 Invariant Labs, Toxic Agent Flow 공개
2025.06.16 Simon Willison, 치명적 3요소 개념 정리
2025.06.24 Snyk, Invariant Labs 인수 발표
2025.12.10 GitHub, Lockdown 모드와 콘텐츠 정화(기본 적용), 도구 단위 설정(X-MCP-Tools) 발표
2026.06 CVE-2026-48529 공개 — HTTP 모드 Lockdown이 첫 사용자 자격증명으로 권한을 확인하던 결함 (0.22.0 ~ 1.1.2 미만, 1.1.2에서 수정)
2026.08.19 v1.10.0 — 서버 Lockdown을 요청이 완화할 수 없게 고정, 호출자별 캐시 분리, 정화 로직 강화
2026.08.25 v1.11.0 — 작성 시점 최신 릴리스 (도구 호출별 OAuth 권한 확인 등)

콘텐츠 정화 (기본 적용)

이슈·PR 본문을 모델에 넘기기 전에 사람 눈에는 안 보이지만 모델에는 읽히는 부분을 걸러냅니다. 보이지 않는 유니코드 문자, 위험한 HTML 태그·속성, 렌더링되지 않는 마크다운 조각이 대상입니다. 숨겨 둔 지시는 줄여 주지만, 눈에 보이는 평문으로 쓴 지시까지 막지는 못합니다.

Lockdown 모드

공개 저장소에서 푸시 권한이 있는 사람이 쓴 내용만 에이전트에 보여 줍니다. 외부 기여자가 쓴 이슈·PR 본문은 오류로 막고, 댓글·리뷰는 걸러 냅니다. 비공개 저장소에는 영향이 없습니다. 이번 사례의 출발점인 "외부인이 쓴 공개 이슈"를 직접 겨냥한 기능입니다.


🛠 조치 방법 — 흐름을 어디서 끊을까

공격 흐름의 각 단계마다 끊을 수 있는 통제가 하나씩 있습니다. 하나만으로는 부족하니 겹쳐서 적용하는 것이 원칙입니다.

통제 무엇을 끊나 한계
토큰 범위 Fine-grained 토큰을 필요한 저장소만 선택해 발급 → 비공개 저장소 접근 자체를 제거 작업마다 토큰을 나눠야 해서 번거로움
읽기 전용 쓰기 도구를 모두 비활성화 → PR·이슈 생성으로 내보내는 통로 차단 토큰 권한을 줄이는 것은 아님
도구 제한 필요한 도구만 켜기, 위험 도구 제외 → 공격에 쓸 수 있는 도구 축소 토큰이 허용하는 범위보다 넓어지거나 좁아지진 않음
Lockdown 외부 기여자의 공개 저장소 글을 모델에서 제외 → 주입 입구 축소 최선 노력형 필터, 인가 경계 아님
승인 유지 쓰기 도구 호출은 매번 확인 → 사람이 마지막에 차단 피로도 때문에 형식적 승인으로 흐르기 쉬움
세션 분리 공개 저장소 작업과 비공개 저장소 작업을 다른 세션·토큰으로 → 3요소가 한곳에 모이지 않게 사용 습관을 바꿔야 함

설정 예시

공식 문서 기준 옵션 이름입니다. 로컬 서버는 플래그(또는 환경변수), GitHub가 호스팅하는 원격 서버는 요청 헤더로 지정합니다. 아래는 "이슈와 PR만 읽기 전용으로, Lockdown 켜고" 쓰는 예입니다.

 

로컬 서버 (stdio)

github-mcp-server stdio \
  --toolsets=issues,pull_requests \
  --read-only \
  --lockdown-mode

원격 서버 (HTTP 헤더)

{
  "type": "http",
  "url": "https://api.githubcopilot.com/mcp/",
  "headers": {
    "X-MCP-Toolsets": "issues,pull_requests",
    "X-MCP-Readonly": "true",
    "X-MCP-Lockdown": "true"
  }
}
설정 로컬 서버 원격 서버
도구 묶음 --toolsets / GITHUB_TOOLSETS X-MCP-Toolsets
개별 도구 --tools / GITHUB_TOOLS X-MCP-Tools
도구 제외 --exclude-tools / GITHUB_EXCLUDE_TOOLS X-MCP-Exclude-Tools
읽기 전용 --read-only / GITHUB_READ_ONLY X-MCP-Readonly 또는 /readonly 경로
Lockdown --lockdown-mode / GITHUB_LOCKDOWN_MODE X-MCP-Lockdown

아무것도 지정하지 않으면 기본 도구 묶음(context, issues, pull_requests, repos, users)이 켜지고, 이 안에는 PR 생성 같은 쓰기 도구도 포함됩니다. 읽기 전용 모드는 다른 설정보다 우선해서 쓰기 도구를 끕니다.

⚠️ Lockdown을 과신하지 마세요

공식 문서는 Lockdown 모드를 프롬프트 인젝션 위험을 줄이는 최선 노력형 콘텐츠 필터이지 인가 경계가 아니라고 명시합니다. 토큰이 원래 읽고 쓸 수 있는 범위는 그대로이고, 걸러진 내용도 다른 도구나 같은 토큰의 API 호출로 닿을 수 있습니다.

또 자동화 출력이 걸러지지 않도록 github-actions[bot]과 copilot 계정이 쓴 내용은 푸시 권한과 관계없이 신뢰 대상으로 취급합니다.

HTTP 모드로 여러 사용자가 함께 쓰는 서버를 직접 운영한다면 CVE-2026-48529가 수정된 1.1.2 이상인지 반드시 확인하세요. 가능하면 최신 릴리스로 올리는 것이 좋습니다.


✅ 점검 체크리스트

GitHub MCP를 이미 쓰고 있다면 아래 순서로 확인해 보세요. 예를 들어 "오픈소스 이슈 정리용 에이전트"라면 공개 저장소만 읽는 토큰 + 읽기 전용 + Lockdown 조합이면 충분한 경우가 많습니다. (특정 조직과 무관한 일반화 예시입니다.)

점검 항목 무엇을 확인하나
토큰 종류 계정 전체 권한의 클래식 토큰 대신 저장소를 선택한 Fine-grained 토큰을 쓰는가
저장소 범위 공개 저장소 작업용 토큰에 비공개 저장소가 섞여 있지 않은가
쓰기 필요성 조회·요약 위주 작업인데 쓰기 도구가 켜져 있지 않은가
도구 목록 기본값 그대로가 아니라 필요한 도구 묶음·도구만 지정했는가
Lockdown 외부인이 글을 쓸 수 있는 공개 저장소를 다룬다면 켜져 있는가
승인 정책 쓰기 도구에 "항상 허용"을 걸어 두지 않았는가
서버 버전 직접 운영하는 서버가 최신 릴리스이거나 최소 1.1.2 이상인가
기록 확인 에이전트가 만든 PR·이슈·댓글을 주기적으로 검토하는가

💡 팁

도구를 줄이면 보안뿐 아니라 비용에도 이득입니다. GitHub는 자주 쓰는 도구 3~10개만 불러오면 기본 도구 묶음 전체를 불러올 때보다 컨텍스트 사용량이 약 60~90% 줄었다고 밝혔습니다.


💬 자주 묻는 질문

Q. GitHub가 이 취약점을 패치했나요?

서버 코드 결함이 아니어서 "패치 완료"라는 개념이 맞지 않습니다. 대신 콘텐츠 정화, Lockdown 모드, 도구 단위 설정 같은 완화 기능이 추가됐고, 이를 켜고 권한을 줄이는 것은 사용자 몫입니다.

Q. Claude에서만 생기는 문제인가요?

아닙니다. 시연은 Claude Desktop으로 했지만, 연구진은 기반 모델이나 구현과 관계없이 GitHub MCP 서버를 쓰는 모든 에이전트에 해당한다고 밝혔습니다.

Q. 비공개 저장소만 쓰면 안전한가요?

외부인이 쓴 글을 읽지 않는다면 3요소 중 '외부 입력'이 크게 줄어듭니다. 다만 외부 기여자가 있는 저장소, 웹 검색이나 메일 같은 다른 MCP 도구를 함께 연결했다면 다른 경로로 외부 입력이 들어올 수 있습니다. 연결된 도구 전체를 기준으로 판단해야 합니다.

Q. Lockdown만 켜면 되지 않나요?

공식 문서가 직접 인가 경계가 아니라고 밝힌 기능입니다. 입구를 좁히는 보조 수단으로 보고, 토큰 범위와 읽기 전용 설정을 기본으로 깔아 두세요.


🎉 정리

이번 사례가 보여 준 것은 "신뢰할 수 있는 도구만 써도 조합에 따라 유출 통로가 된다"는 점입니다. 기능은 점점 좋아지고 있지만, 공식 문서조차 필터를 경계선으로 보지 말라고 말합니다.

에이전트를 연결할 때마다 "이 세션은 비공개 데이터, 외부 입력, 외부 전송 중 무엇을 동시에 갖고 있나?"를 한 번 물어보세요. 셋이 모두 켜져 있다면, 하나를 끄는 것부터 시작하면 됩니다.


🔗 참고 자료