Plugin4Shell – 상위 4개 코딩 에이전트에서 발견된 제로 클릭 RCE 취약점
요약
본 기사는 AI 코딩 에이전트 생태계에서 발견된 심각한 공급망 취약점인 Plugin4Shell을 다룹니다. 공격자가 플러그인의 레포지토리를 통제하여, SHA 고정(pinning) 메커니즘을 우회하는 제로 클릭 원격 코드 실행(RCE)이 가능함을 보여줍니다. 이는 Claude Code, Codex, GitHub Copilot 등 주요 에이전트 전반에 영향을 미치는 업계적 문제입니다.
핵심 포인트
- AI 에이전트 생태계의 새로운 공급망 취약점 발견
- 공격자는 레포지토리 통제를 통해 SHA 고정을 우회 가능
- 사용자 상호작용 없이 시스템 전체가 손상되는 제로 클릭 RCE 발생
- 취약점은 특정 제품 문제가 아닌 업계 전반의 설계 오류
요약 (TL;DR)
사용자가 마켓플레이스에서 완전히 안전한 플러그인을 설치합니다. 이 마켓플레이스는 해당 플러그인의 검증된 커밋을 고정(pin)하여, 이것이 안전하며 계속 안전할 것이라고 신뢰하게 만듭니다.
만약 '안전한' 플러그인의 레포지토리가 공격자에 의해 통제된다면, 공격자는 기본 브랜치(default branch)를 악성 버전으로 설정할 수 있습니다. 그러면 설치하는 모든 사용자에게 악성 버전이 제공되는데, 이는 SHA 고정(SHA pinning)이 보호하기 위해 존재하는 바로 그 상황입니다.
상황은 에이전트가 마켓플레이스에서 플러그인을 자동 업그레이드한다는 점을 고려하면 더욱 심각해집니다. 공격자는 역시 무해한 새 버전을 가지고, PR(Pull Request)을 열어 마켓플레이스의 고정된 SHA를 이 새 버전으로 변경할 수 있습니다. 마켓플레이스 소유자가 이를 승인하면 – 해당 '러그 풀(rug-pull)'이 발생하며, 이제 플러그인을 설치한 모든 사용자는 악성 버전으로 자동 업그레이드됩니다.
지금까지의 이야기
이것은 우리가 전하고 온 이야기의 세 번째 막입니다. The Story of Skills에서는 침투가 얼마나 쉬운지 보여주었습니다. 우리는 악성 스킬을 만들고, 이것이 바이럴 되는 것을 지켜본 후, 26,000개 이상의 에이전트를 장악했습니다. 사람들이 신뢰하는 마켓플레이스에 코드를 심는 것이 어려운 일은 아닙니다. SkillJacking에서는 아무것도 심을 필요조차 없다는 것을 보여주었습니다. 925개의 스킬이 이미 사용되고 있었는데, 이들이 관리자들로부터 탈취되어 134,000개의 에이전트에 영향을 미쳤습니다. 업계에서 바로 이런 종류의 '러그 풀'에 대한 답변은 SHA 고정입니다. 즉, 하나의 커밋 코드를 검토하고, 그 커밋을 고정한 다음, 고정된 커밋이 영원히 실행될 것이라고 신뢰하는 것입니다. Plugin4Shell은 이 경계가 무너진 이야기입니다.
이는 플러그인 SHA 고정 우회(bypass) 취약점입니다: 에이전트는 마켓플레이스가 고정한 정확한 커밋을 체크아웃하지만, 그것이 실제로 그곳에 도달했는지 결코 검증하지 않습니다. 따라서 플러그인의 레포지토리를 통제하는 공격자는 체크아웃이 악성 코드로 해석되도록 만들 수 있으며, 이때도 고정된 SHA는 여전히 유효해 보입니다. 그 결과는 Claude Code, Codex, GitHub Copilot, 그리고 Gemini CLI 전반에 걸친 제로 클릭 원격 코드 실행(zero-click remote code execution)입니다.
Air Marketplace와 Air Filter를 사용하는 기업들은 Plugin4Shell의 영향을 받지 않았습니다.
.png
AI 에이전트 생태계에서 처음 발견된 공급망 취약점입니다. 이전의 에이전트 보안 작업은 모델이나 에이전트 자체를 겨냥해 왔습니다. Plugin4Shell은 그 아래에 있는 배포 계층, 즉 에이전트 애드온이 수백만 대의 장치에 도달하는 마켓플레이스를 공격합니다.제로 클릭 원격 코드 실행(RCE)입니다. 어떠한 사용자 상호작용도 필요하지 않습니다. 그 결과는 에이전트와 그것이 실행되는 호스트 전체가 완전히 손상되며, 이로 인해 에이전트가 접근할 수 있는 모든 자산과 모든 데이터에 대한 완전한 접근 권한을 얻게 됩니다.하나의 결함으로 모든 주요 연구소에서 이것이 발생했습니다. 동일한 설계 오류가 영향을 받는 모든 에이전트에 존재합니다. 이는 특정 제품에서의 구현 실수가 아니라, 업계 전반에 걸쳐 반복된 단일 실수이며, 수백만 개의 에이전트를 취약하게 만듭니다.마켓플레이스만으로는 이를 완전히 막을 수 없습니다. 패치는 에이전트 내부에서 해결되므로, 오직 에이전트 측의 수정만이 보증을 복원합니다. 마켓플레이스는 SHA 형태의 이름을 거부하는 호스트만을 허용하여 분기 이름(branch-name) 변종을 완화할 수는 있지만—사실상 GitHub 전용으로 제한하는 것과 같음—이는 에이전트가 공식적으로 지원하는 호스트를 차단하며, Gemini CLI의 변종에 대해서는 아무런 효과도 없습니다.## 누가 영향을 받으며 영향은 무엇인가** 마켓플레이스에서 플러그인을 설치하는 주요 코딩 에이전트를 실행하는 모든 사람이 노출됩니다. 여기에는 Claude Code, OpenAI Codex, GitHub Copilot, 그리고 Gemini CLI가 포함됩니다. 이러한 노출은 단순히 플러그인을 부주의하게 설치하는 사용자에게만 국한되지 않습니다. 피해자는 단지 신뢰하는 마켓플레이스에서 검토되었고 보안 모델이 의도한 대로 정확히 고정(pin)된 플러그인 하나만 설치되어 있으면 됩니다.올바른 일을 한다고 해서 보호받는 것은 아닙니다. 커뮤니티 마켓플레이스를 넘어 플러그인을 검토하고 승인된 커밋에 고정하는 조직들은 자신들의 안전장치로 SHA 고정을 신뢰하지만, Plugin4Shell은 이를 조용히 무효화합니다. 검토가 통과되고, 고정이 기록되며, 다른 코드가 설치되는 것입니다. 고정에 기반한 모든 다운스트림 심사 과정이 실패를 물려받습니다.}**
[번역된 제목]: Plugin4Shell – 상위 4개 코딩 에이전트에서 발견된 제로 클릭 RCE 취약점}**
{
0-click으로 가능한 이유는 플러그인 자동 업데이트 덕분입니다. 에이전트들은 설치된 플러그인을 백그라운드에서 업데이트합니다. Claude Code와 Codex에서는 이것이 기본 기능이기 때문에, 고정 커밋(pinned commit)이 상위 버전으로 교체되면 사용자가 이미 신뢰하고 설치한 플러그인이 사용자 상호작용 없이 악성 버전으로 대체됩니다. 즉, 설치 단계도 없고, 프롬프트도 없으며, 눈치챌 것도 없습니다. 공격자는 누구에게서든 새로운 것을 설치하도록 설득할 필요가 없습니다. 단지 그 온화한(benign) 플러그인이 이미 존재하기만 하면 됩니다.
악용 방법
공격자가 마켓플레이스를 제어할 필요는 없으며, 두 가지 경로가 있습니다.
방법 1: 플러그인을 게시하고, 나중에 이를 악성으로 변경한다. 공격자는 신뢰받는 마켓플레이스에 진정으로 온화한(benign) 플러그인을 기여하여 검토를 통과시킨 다음, 나중에 그 내용을 악성 버전으로 교체합니다. 상위 마켓플레이스에 플러그인을 올리는 것은 가설이 아닙니다. 저희가 이미 해봤습니다 (Skills의 이야기).
방법 2: 합법적인 작성자의 플러그인을 탈취한다. 공격자는 다른 사람이 작성했고 마켓플레이스가 이미 신뢰하는 플러그인의 저장소(repository)를 장악한 다음, Plugin4Shell을 이용해 해당 플러그인을 설치한 모든 에이전트에 악성 버전을 강제 적용합니다. 이는 바로 이러한 상황을 막기 위해 존재하는 버전 고정(version pinning) 메커니즘을 우회하는 것입니다. 저희는 SkillJacking과 RepoJacking에서 실제 환경에서 이 장악 단계를 시연했습니다. 종합적으로 볼 때, 이 체인 전체가 종단 간(end to end)으로 증명되었습니다. 즉, 장악은 대규모로 발생하며, Plugin4Shell은 이를 봉쇄하기 위해 만들어진 메커니즘을 무력화시킵니다.
공격 과정, 전 과정을 거쳐서:
기술 심층 분석
영향을 받는 모든 에이전트는 고정 커밋(pinned commit)을 체크아웃하지만, 실제로 그곳에 도착했는지 확인하지 않습니다. 이 빠진 하나의 확인 절차가 전체 버그이며, git은 공격자에게 이를 악용할 두 가지 방법을 제공합니다.
고정 커밋이 브랜치가 되는 경우 - Claude Code, Codex, GitHub Copilot
이 에이전트들은 플러그인 저장소를 클론하고 고정된 SHA를 체크아웃합니다:
git clone <플러그인 저장소> ./
git checkout aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
공격자는 이제 상위 저장소(upstream repository)를 제어하게 되었고, 이름이 정확히 40진수 16진수로 고정된 SHA인 브랜치를 생성한 뒤 이를 저장소의 기본값으로 설정합니다. 따라서 단순한 git clone 명령어만 실행해도 해당 이름의 로컬 브랜치로 가져와집니다. 이후 git checkout을 사용하면 이 고정된 SHA가 해당 브랜치로 해결됩니다. 이름이 유효한 참조(ref)이자 객체 ID인 경우, git은 참조를 우선시하고 단순히 'refname is ambiguous'라는 경고만 출력하므로, 고정된 커밋이 여전히 존재하는지 여부는 중요하지 않습니다. 즉, 체크아웃되는 것은 브랜치입니다. 이 취약점이 작동하기 위해서는 두 가지 조건이 필요합니다. 첫째, 브랜치가 해시처럼 이름 지어지는 것을 막는 것이 없어야 합니다 (git 자체의 git check-ref-format은 40진수 16진수 이름을 허용하며, 해당 프로토콜을 따르는 호스팅 환경도 이를 허용합니다). 둘째, 해당 브랜치가 저장소의 기본값이어야 합니다. 기본값이 아닌 브랜치는 원격 추적 참조(remote-tracking ref)로만 가져와지며, 체크아웃 시 커밋으로 되돌아가게 됩니다. 이제 작업 디렉터리(working tree)는 공격자가 제어하게 되었고, 에이전트는 고정된 커밋에서 성공적인 설치를 보고합니다.
이는 단순히 설치 시점의 버그일 뿐만 아니라, 이것이 '제로 클릭(zero-click)'으로 만드는 이유입니다. 동일한 git checkout 명령어가 백그라운드 자동 업데이트에서도 재실행되기 때문입니다 (Claude Code와 Codex에서 기본값). 따라서 마켓플레이스가 고정된 SHA를 변경하더라도 사용자 조치 없이 이미 설치된 플러그인에 이 스왑이 도달합니다.
이는 브랜치를 해시처럼 이름 지을 수 있는 곳에서만 작동합니다. 이는 git의 기본 동작이지만, 일부 호스팅 환경에서는 이를 금지합니다. GitHub는 40진수 16진수 브랜치 이름을 아예 거부하는 반면, Bitbucket 등 다른 곳과 모든 자체 호스팅(self-hosted) git 서버는 이를 허용합니다. 이러한 호스트의 마켓플레이스는 지원되는 구성이며, Anthropic 자체 문서에서도 Bitbucket과 자체 호스팅 git을 유효한 마켓플레이스 백엔드로 나열하고 있습니다.
고정된 SHA가 가져와지지만 체크아웃되지는 않는 경우 - Gemini CLI
Gemini는 --ref를 사용하여 고정하고 세 단계에 걸쳐 설치합니다:
`git clone --depth 1 <플러그인 저장소> ./
git fetch origin 41d0bc0a4aeb2fbf797dacea39e876d98c95024b
git checkout FETCH_HEAD`
이 fetch는 올바른 커밋을 검색하여 .git/FETCH_HEAD에 기록합니다.
. 하지만 git checkout FETCH_HEAD는 해당 파일을 읽을 필요가 없습니다. 만약 저장소의 기본 브랜치 자체가 FETCH_HEAD라는 이름이라면, 체크아웃은 그 브랜치로 해결되고, 가져온 커밋(fetched commit)은 공격자가 제어하는 기본 브랜치 내용에 밀려 조용히 무시됩니다.
이러한 두 가지 변형 모두를 막는 주장은 다음과 같습니다. 체크아웃 후, 실제 작업 트리(working tree)에 있는 커밋을 해결하고, 그것이 고정된 SHA와 같지 않으면 중단해야 합니다.
test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort
요청된 참조(ref)가 아니라 해결된 HEAD를 확인해야 합니다. 이 구분이 바로 Gemini 변형에서 빠지는 부분입니다. 그리고 이는 에이전트 내부에서 실행되어야 합니다. 고정 값(pin)은 클라이언트에서 해결되기 때문에, 어떤 마켓플레이스도 광고하는 보증을 강제할 수 없습니다.
완화 방법 (How it can be mitigated)
고정 값이 에이전트 내부에서 해결되므로, 어떤 마켓플레이스도 이를 강제할 수 없습니다. 따라서 수정 사항은 에이전트에 포함되어야 하며, 업데이트가 존재하는 유일한 완전한 완화책입니다:
Claude Code - Anthropic은 저희의 공개 이후 2.1.179 버전에서 패치했습니다.Codex - OpenAI는 저희의 공개 이후 0.146.0 버전에서 패치했습니다.GitHub Copilot - 저희가 Microsoft에 동일한 결함을 공개했지만, 아직 수정 사항을 배포하지 않았기 때문에 사용자는 패치가 없습니다.Gemini CLI - Google은 Gemini CLI를 사용 중단(deprecated)했으며 패치할 계획이 없으므로, 모든 설치는 영구적으로 취약합니다. 해당 사용자들은 이 공격의 영향을 받지 않는 Antigravity로 마이그레이션해야 합니다. (이는 마켓플레이스 플러그인 SHA 고정 기능이 없어 우회할 수 없습니다.)
타임라인 (Timeline)
Air Marketplace와 Air Filter를 사용하는 기업은 Plugin4Shell의 영향을 받지 않았습니다. Air가 에이전트 공급망 취약점으로부터 어떻게 보호할 수 있는지 더 자세히 알아보기 위해 데모를 예약하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code Search의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기