라이브러리로 돌아가기
보안 및 거버넌스

SHA 고정은 검증이 아니다: Plugin4Shell과 최초의 AI 에이전트 공급망 RCE

최종 업데이트: 2026年9月18日

925개의 플러그인 스킬이 이미 원래 유지보수자로부터 탈취되었고, 그 스킬들은 134,000개 에이전트에 닿아 있습니다. 2026년 9월 17일, AIR Security가 Plugin4Shell을 공개했습니다 — AI 에이전트 생태계 최초의 공급망 취약점입니다. Claude Code, OpenAI Codex, GitHub Copilot, Google Gemini CLI에 영향을 미치는 제로클릭 원격 코드 실행(RCE)으로, 모두 같은 누락된 검사를 통해 발생합니다. 메커니즘은 영향을 받은 모든 에이전트가 건너뛰는 단 하나의 git 단언입니다. 에이전트는 marketplace가 고정한 커밋 SHA를 체크아웃하지만, 작업 트리가 실제로 그 커밋에 도착했는지는 검증하지 않습니다. 플러그인 저장소를 장악한 공격자는 고정된 40자 SHA를 브랜치 이름으로 붙여 저장소 기본값으로 만들고, 에이전트는 고정된 커밋에 깨끗하게 설치되었다고 보고하는 동안 공격자가 제어한 코드를 설치합니다(Cyber Security News; Help Net Security).

이것이 프로덕션 시스템을 상대로 코딩 에이전트를 운영하는 모든 팀에게 중요한 이유는, 핀(pinning)이 곧 통제였기 때문입니다. 커뮤니티 marketplace 너머로 나아간 조직들 — 플러그인 코드를 검토하고 설치를 검토된 커밋에 고정하는 조직들 — 은 SHA 고정을 자신들의 안전장치로 신뢰했고, Plugin4Shell은 그것을 조용히 무효화합니다. 검토는 통과하고, 핀은 기록되고, 다른 코드가 실행됩니다(AIR). 이 글은 다음 플러그인 자동 업데이트가 발동하기 전에 엔지니어링 책임자가 알아야 할 네 가지를 다룹니다. git 명령 하나로 설명되는 메커니즘, 양성 채택에서 백그라운드 RCE까지의 5단계 공격, 벤더 대응 스코어보드(2개 수정, 1개 미수정, 1개 지원 중단 및 미수정), 그리고 에이전트가 설치하는 고정된 모든 아티팩트 — 플러그인, MCP 서버, 스킬 — 의 격차를 메우는 검증 항목입니다.

핵심 요약

  • 제로클릭 RCE가 하나의 누락된 git 단언을 통해 4대 코딩 에이전트 전부 — Claude Code, Codex, GitHub Copilot, Gemini CLI — 를 타격했습니다 — AIR는 2026년 9월 17일 Plugin4Shell을 공개했습니다. 에이전트는 marketplace가 고정한 커밋 SHA를 체크아웃하면서도 체크아웃이 그 커밋으로 해석되었는지는 검증하지 않습니다(AIR).
  • 925개의 스킬이 이미 유지보수자로부터 탈취되어 134,000개 에이전트에 도달했습니다 — AIR의 SkillJacking 연구입니다. Plugin4Shell은 바로 이런 저장소 탈취를 억제하기 위해 만들어진 SHA 고정 메커니즘을 무력화합니다(AIR).
  • Git은 해시 자체보다 해시와 같은 이름의 브랜치를 우선합니다 — 고정된 40자 SHA를 이름으로 가진 브랜치가 저장소 기본값으로 설정되면 git checkout <sha>가 공격자 코드로 리디렉션됩니다. Gemini CLI 변형은 대신 FETCH_HEAD를 공격면으로 삼습니다(Cyber Security News).
  • 벤더 스코어보드는 2개 수정, 1개 미수정, 1개 지원 중단 및 미수정입니다 — Anthropic은 Claude Code를 2.1.179에서, OpenAI는 Codex를 0.146.0에서 수정했습니다. Microsoft는 Copilot 수정을 배포하지 않았고, Google은 Gemini CLI를 미수정 상태로 지원 중단했으므로 기존 설치 전부가 계속 노출됩니다(Help Net Security).
  • 두 변형을 모두 막는 것은 하나의 단언입니다: 체크아웃 후 해석된 HEAD를 고정 SHA와 대조하라test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort — 그리고 그 검사는 에이전트 내부에서 실행되어야 합니다. marketplace는 자신이 해석하지 않는 핀을 강제할 수 없기 때문입니다(AIR).

아래 다이어그램은 이 공개를 1분으로 압축합니다. 5단계 공격 사슬, 3일 시점의 벤더 스코어보드, 그리고 격차를 막는 단언입니다.

SHA 고정은 검증이 아니다 Plugin4Shell: 누락된 git 단언 하나, 4대 코딩 에이전트 모두에서 제로클릭 RCE — AIR, 2026년 9월 17일 끝에서 끝까지의 공격 1 심기 양성 플러그인을 커밋 aaa…aaa에 고정. 검토 통과. 2 채택 설치는 검토되고 신뢰된 커밋에 고정되어 진행됩니다. 3 재고정 일상 업데이트: marketplace가 핀을 bbb…bbb로 올립니다. 4 낙하 bbb…bbb 브랜치가 기본값이 되고 — 공격 코드를 가리킵니다. 5 RCE 자동 업데이트가 브랜치를 체크아웃. 클릭 없음, 프롬프트 없음, 아무것도 보이지 않음. 벤더 대응 — 2개 수정, 1개 미수정, 1개 지원 중단 및 미수정 Anthropic Claude Code 수정됨 2.1.179에서 수정 OpenAI Codex 수정됨 0.146.0에서 수정 Microsoft GitHub Copilot 수정 없음 GitHub의 이름 금지로는 부족 Google Gemini CLI 지원 중단 미수정 — Antigravity로 이주 수정 — 체크아웃 후 검증 test "$(git rev-parse HEAD)" = "<pinned-sha>" || abort 1. 요청한 ref가 아니라 해석된 HEAD — 작업 트리가 실제로 담고 있는 것 — 를 검사하라. 2. 검사는 에이전트 내부에서 실행하라. 핀은 클라이언트에서 해석되며 marketplace가 강제할 수 없다. 3. 수정이 없는 곳(Copilot, Gemini CLI)은 수정이 배포될 때까지 에이전트의 접근 범위를 제한하라. 탈취 경제의 규모(AIR) 925 탈취된 스킬 134,000 도달한 에이전트 4/4 영향받은 주요 에이전트 2/4 미수정 벤더 검증하지 않는 핀은 제안에 불과합니다. 체크아웃을 검증하고 — 그다음 에이전트를 업데이트하라. 수정이 없는 곳에서는 핀 뒤에 어떤 보장도 없습니다. Plugin4Shell — AI 에이전트 공급망의 최초 취약점 — ideabosque.com/library

메커니즘: 하나의 단언, 네 개의 에이전트

SHA 고정은 marketplace 보안 모델이 설계대로 작동하는 상태입니다. 검토자가 한 커밋에서 플러그인을 검사하고, marketplace가 그 커밋의 SHA를 기록하고, 에이전트는 영원히 정확히 그 코드를 설치해야 합니다. 실패는 마지막 단계에 있습니다. 영향을 받은 모든 에이전트는 대략 이런 시퀀스를 실행합니다(AIR):

git clone  ./
git checkout aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   # 고정된 SHA

그리고 체크아웃이 실제로 고정된 커밋에 착지했는지 묻지 않습니다. 이 누락이 악용 가능한 이유는 git이 객체보다 이름을 먼저 해석하기 때문입니다. 어떤 이름이 유효한 ref이자 커밋 해시일 때 git은 ref를 우선하고 refname is ambiguous 경고만 출력합니다. 이미 상류 저장소를 장악한 공격자는 정확한 40자 16진수 고정 SHA와 같은 이름의 브랜치를 만들어 저장소 기본값으로 설정합니다. 일반적인 git clone은 그 브랜치를 로컬 ref로 가져오고, git checkout <sha>는 브랜치로 해석되며, 작업 트리는 공격자 제어하에 놓이고 에이전트는 고정된 SHA에서의 설치 성공을 보고합니다(Cyber Security News).

두 가지 조건이 이 기법을 가능하게 합니다. 첫째, 해시와 같은 이름의 브랜치를 보편적으로 막는 규칙은 없습니다. git 자신의 check-ref-format은 40자 16진수 이름을 받아들이고, GitHub는 완전히 거부하지만 Bitbucket과 자체 호스팅 git 서버는 허용합니다 — 그리고 Anthropic의 문서는 Bitbucket과 자체 호스팅 git을 유효한 marketplace 백엔드로 나열합니다(AIR). 둘째, 브랜치는 저장소 기본값이어야 합니다. 기본값이 아닌 브랜치는 원격 추적 ref로만 도착하며 체크아웃은 실제 커밋으로 폴백합니다.

Gemini CLI는 다르게 실패합니다. 설치 시퀀스는 고정된 커밋을 fetch한 다음 FETCH_HEAD를 체크아웃합니다:

git clone --depth 1  ./
git fetch origin 41d0bc0a4aeb2fbf797dacea39e876d98c95024b
git checkout FETCH_HEAD

저장소 기본 브랜치 자체가 FETCH_HEAD라는 이름이라면 체크아웃은 그 브랜치로 해석되고 fetch한 커밋을 조용히 버립니다(AIR). 명령은 달라도 근본 원인은 같습니다. 에이전트는 자신이 요청한 이름을 신뢰하고 받은 커밋을 검증하지 않습니다.

끝에서 끝까지의 공격: 채택에서 RCE까지

두 공격 경로 모두 marketplace 장악을 필요로 하지 않습니다. AIR는 둘 다 시연했습니다:

  1. 심기. 공격자는 진짜로 양성인 플러그인을 커밋 aaa…aaa에 고정해 게시합니다. 검토를 통과합니다.
  2. 채택. 사용자들이 설치합니다. 모든 설치는 검토된 커밋에 고정됩니다.
  3. 재고정. 공격자는 여전히 양성인 일상 업데이트를 게시하고, marketplace가 핀을 bbb…bbb로 올립니다.
  4. 낙하. 공격자는 bbb…bbb라는 이름의 브랜치를 만들어 저장소 기본값으로 설정하고 악성 코드를 가리킵니다. 고정된 커밋 자체는 그대로 둘 수 있습니다.
  5. 자동 업데이트에서 RCE로. 바뀐 핀이 모든 에이전트의 백그라운드 자동 업데이트를 트리거합니다 — Claude Code와 Codex의 기본 동작 — 체크아웃은 새 핀을 브랜치로 해석하고, 클릭 없이, 프롬프트 없이, 재설치 없이 코드가 실행됩니다(AIR).

대안 경로는 더 빠릅니다. 정당한 유지보수자의 저장소를 탈취해 심기 단계를 아예 건너뛰는 것입니다. AIR의 자매 연구는 이것이 이미 얼마나 흔한지 정량화합니다 — 925개 스킬이 원래 유지보수자로부터 탈취되어 134,000개 에이전트에 도달했습니다(AIR). 이것은 3부작의 3막입니다. The Story of Skills는 악성 스킬이 26,000개 에이전트에 도달하는 모습을 보여줬고, MCPJacking은 만료 도메인을 통해 공식 marketplace의 155개 탈취 가능한 MCP 서버를 발견했습니다. 연구자들은 그 도메인들을 등록해 그들을 신뢰하는 모든 에이전트에서 원격 프롬프트 실행을 얻었습니다(AIR). Plugin4Shell은 업계가 이 모든 것을 억제하려고 만든 메커니즘의 경계 실패입니다. 폭발 반경은 에이전트보다 넓습니다. 플러그인과 애드온은 에이전트를 실행하는 개발자의 권한을 상속합니다 — 로컬 소스 코드, 클라우드 자격 증명, SSH 키, 내부 저장소, 그리고 프로덕션 시스템입니다(Cyber Security News).

벤더 스코어보드: 두 개 수정, 하나 미수정, 하나 지원 중단 및 미수정

공개 타임라인은 조정된 공개가 작동했다는 것 — 그리고 어디서 멈췄는지 — 를 보여줍니다:

언제 무엇을
2026년 5월 AIR가 결함 발견, 4개 에이전트 모두 상대로 동작하는 PoC 확보
2026년 6월 4개 벤더에 조정된 공개
2026-06-17 Anthropic, Claude Code 2.1.179에서 수정 확인
2026-08-04 Google, 수정이 배포되지 않을 것임을 확인 — Gemini CLI 지원 중단, 사용자는 Antigravity로 이주 안내
2026-08-12 OpenAI의 Codex 0.146.0 수정 확인
2026-09-17 공개

9월 18–19일 기준 스코어보드는 변함없습니다. Anthropic 수정, OpenAI 수정, Microsoft는 Copilot 수정 미배포, Google은 Gemini CLI를 미수정 상태로 지원 중단 — 즉 기존 Gemini CLI 설치 전부가 무기한 노출 상태로 남습니다(Help Net Security). GitHub의 대응 — 플랫폼에서 SHA 모양의 브랜치·태그 이름 금지 — 는 격차를 닫지 못합니다. marketplace는 Bitbucket이나 자체 호스팅 git 서버에서 호스팅될 수 있고 그곳에서는 그런 이름이 여전히 합법이기 때문입니다(Cyber Security News).

AIR의 요약이 가장 정직합니다. "The fix has to ship in the agent, and updating is the only complete mitigation where one exists" (AIR). 구조적 이유는 조달 대화를 위해 다시 강조할 가치가 있습니다. 핀은 에이전트 내부에서 해석되므로 marketplace는 자신이 광고하는 보장을 강제할 수 없습니다. 벤더 측 marketplace 업로드 스캔(Anthropic은 2026년 8월 6일 Skill/Plugin Scanning 제공)은 악성 플러그인이 marketplace에 들어올 확률을 낮추지만, 에이전트 측 체크아웃 검증을 대체할 수는 없습니다. 교체는 검토 이후, 해석 시점에 일어나기 때문입니다(MCP Security Hardening Checklist). 이것은 또한 거버넌스 사례이기도 합니다. 4개 벤더, 하나의 공유 설계 결함, 그리고 사흘째 이어지는 비대칭 대응 — 구매 조직은 이것을 한 벤더의 보안 패치 속도를 축소판으로 읽을 수 있습니다.

체크아웃 후 검증: 일반화되는 통제

AIR의 한 줄 수정이 두 변형을 모두 막습니다(AIR):

test "$(git rev-parse HEAD)" = "" || abort

세부 사항이 교훈을 실어 옵니다. git rev-parse HEAD는 작업 트리가 실제로 담고 있는 것을 해석합니다 — 요청한 이름이 아닙니다. 바로 이 구분이 Gemini FETCH_HEAD 변형이 빠져나간 지점입니다. 그리고 검사는 에이전트 내부에서 실행되어야 합니다. 핀은 클라이언트에서 해석되기 때문입니다. 체크아웃 후 검증하는 marketplace는 자기 기록을 검증할 뿐입니다. 불일치 시 중단해야 하는 구성 요소는 에이전트입니다.

이 패턴 — 해석 전이 아니라 해석 후에 검증하기 — 는 에이전트 스택의 고정된 모든 아티팩트 통제로 일반화됩니다. 고정된 MCP 서버 버전, 고정된 스킬, 고정된 모델 가중치, 고정된 컨테이너 digest: 각각은 어떤 설치자가 지킬 것으로 신뢰되고 아무도 그 해석을 검증하지 않는 주장입니다. 같은 누락된 단언은 체크아웃이 일어나는 모든 곳에 존재합니다. 이번 주에 실행할 네 가지 항목:

  1. 수정이 있는 에이전트를 업데이트하라. Claude Code는 2.1.179 이상으로, Codex는 0.146.0 이상으로. Copilot과 Gemini CLI에는 수정이 없습니다 — 수정이 배포될 때까지 이 에이전트들의 접근 범위(파일시스템, 자격 증명, 네트워크 송신)를 제한하거나 벤더의 이주 경로를 따르십시오.
  2. 고정된 모든 아티팩트를 목록화하라. 플러그인, 스킬, MCP 서버 버전, 내부 설치자. 각각에 대해 해석된 HEAD 단언을 건너뛰는 코드 경로가 있는지 확인하십시오 — 여기에는 벤더 에이전트만이 아니라 팀이 작성한 내부 도구도 포함됩니다.
  3. 플러그인 저장소의 탈취 신호를 감사하라. 예상치 못한 브랜치 변경, 기본 브랜치 이동, 소유권 이전. 탈취된 925개 스킬은 이 공개 이전에 이미 빼앗겼습니다. 저장소 탈취는 진입 단계이며 이미 규모 있게 작동 중입니다(Cyber Security News).
  4. 플러그인 자동 업데이트를 편의가 아닌 공급망 전달 채널로 다루십시오. 에이전트가 가져올 수 있는 marketplace와 저장소를 허용 목록에 넣고, 에이전트 구성이 허용하는 곳에서는 재고정을 재검토 아래 두십시오. 제로클릭 속성은 자동 업데이트에서 옵니다 — "제로"를 제거하면 공격은 다시 사용자 행동을 필요로 합니다.

인접한 두 CVE와 상시 노출

같은 주에 Plugin4Shell과 같은 주제를 공유하는 두 개의 MCP 서버 CVE가 나왔습니다 — 호출자를 결코 검증하지 않는 구성 요소에 놓인 신뢰입니다. CVE-2026-54618은 0.2.0 미만의 Obsidian Web MCP에 영향을 미칩니다. OAuth 인가 엔드포인트가 사용자를 인증하지 않은 채 모든 호출자에게 코드를 발급해, 미인증 원격 공격자에게 전체 vault에 대한 읽기·쓰기·검색·이동·삭제 완전 접근을 허용했고 0.2.0에서 수정되었습니다(Rapid7; GitHub advisory GHSA-hwhg-mrjc-8g43). CVE-2026-54446은 NetLicensing-MCP의 인증 누락 결함(CWE-306)입니다(Practical DevSecOps). 이것들은 수개월간 움직이지 않은 생태계 기준 수치 위에 얹힙니다. MCP 월간 다운로드 97M+, 표본 서버의 82%가 경로 순회에 취약, OAuth 사용은 8.5%뿐입니다(Practical DevSecOps).

세 공개에 걸친 패턴은 에이전트 스택의 모든 계층에서 같습니다. 어떤 신뢰 메커니즘 — 핀, OAuth 흐름, 서버 엔드포인트 — 이 잘못된 시점에 검사를 수행하거나 아예 수행하지 않는 것입니다. Plugin4Shell은 단지 하나의 제품에서 에코시스템 전체로 한 번에 넘어간 최초의 사례일 뿐입니다.

함께 읽기


한 중견 산업 유통업체는 내부 도구용으로 Claude Code를 운영하고 NetSuite와 두 공급사 카탈로그를 상대로 견적하는 조달 에이전트를 구동합니다. 팀은 두 표면의 고정된 모든 아티팩트를 목록화하고, Claude Code를 2.1.179로 업그레이드하고, 백그라운드 플러그인 자동 업데이트를 비활성화하고, 내부 MCP 모듈 설치자에 해석된 HEAD 단언을 추가했습니다. 플러그인 소스는 검토된 두 저장소의 허용 목록으로 옮겨지고, 감사 기록은 모든 재고정을 그 diff와 함께 기록합니다. 다음 marketplace 사건은 사건 대응이 아니라 버전 업그레이드와 검토가 됩니다.

범위가 명확한 빌드를 요청하십시오. 1주간의 디스커버리. 시스템 목록, 워크플로 맵, 고정 범위를 받게 됩니다 — 우리와 함께 만들든 아니든.

귀하의 시스템을 위해 이것을 구축하고 싶으신가요?

여기의 각 문서는 실제 프로덕션 작업에서 나왔습니다. 대상 시스템과 워크플로가 있다면, 1주 내에 빌드를 범위 정의할 수 있습니다.

범위 정의 빌드 요청

1주 발견. 시스템 인벤토리, 워크플로 맵, 고정 범위를 받습니다 — 우리와 빌드할지 여부와 관계없이.