SK쉴더스 로고
ADT캡스캡스홈
SK쉴더스

Plugin4Shell: AI 코딩 에이전트 플러그인 검증 우회 취약점

EQST Now | 2026.09.21

NOW Briefing

Brief 1 Claude Code·Codex·GitHub Copilot·Gemini CLI가 플러그인을 고정 커밋으로 내려받은 뒤 실제 그 커밋인지 확인하지 않는 취약점이 공개됐습니다.
Brief 2 공격자가 커밋 해시와 똑같은 이름의 브랜치를 만들면 검증된 플러그인이 악성 코드로 바뀔 수 있고, 자동 갱신 경로에서는 사용자 조작 없이 실행될 수 있습니다.
Brief 3 Claude Code는 2.1.179, Codex는 0.146.0 이상으로 올리고, 패치가 없는 GitHub Copilot과 Gemini CLI는 플러그인 사용을 재검토해야 합니다.

Plugin4Shell: AI 코딩 에이전트 플러그인 검증 우회 취약점

■ 개요

Claude Code·OpenAI Codex·GitHub Copilot·Gemini CLI는 터미널이나 편집기에서 코드를 직접 읽고 고쳐 주는 AI 코딩 에이전트입니다. 네 제품 모두 기능을 확장하는 플러그인을 마켓플레이스에서 내려받으며, 어떤 버전을 쓸지는 40자 16진수 커밋 해시(SHA) 하나로 못 박는 핀 고정 방식으로 정합니다. 엔터프라이즈 AI 에이전트 보안을 다루는 스타트업 AIR는 2026년 9월 17일 네 제품이 이 핀 고정을 실제로 지키지 못한다는 분석을 Plugin4Shell이라는 이름으로 공개했습니다. 국내에서도 SK텔레콤 개발자 커뮤니티 DEVOCEAN에 Claude Code 활용 가이드가 게시될 만큼 이들 도구가 개발 현장에 들어와 있습니다.

에이전트는 고정된 커밋을 체크아웃(저장소에서 특정 버전을 작업 폴더로 꺼내는 동작)한 뒤 실제로 그 커밋이 내려왔는지 확인하지 않아, 저장소를 통제하는 공격자가 고정된 해시와 이름이 같은 브랜치를 미리 만들어 두면 검증을 통과한 플러그인 자리에 악성 코드가 들어갈 수 있습니다. AIR 분석 기준 Claude Code와 Codex는 설치된 플러그인을 배경에서 자동 갱신하는 것이 기본 동작이어서, 이미 설치해 신뢰하고 있던 플러그인이 설치 절차나 승인 창 없이 교체될 수 있습니다. 연구팀은 이 경로로 에이전트와 그 에이전트가 접근할 수 있는 자산·데이터까지 장악할 수 있다고 설명했습니다.

AIR는 2026년 5월 이 취약점을 확인해 6월 벤더에 알렸습니다. Anthropic은 Claude Code 2.1.179에서, OpenAI는 Codex 0.146.0에서 수정을 반영했습니다. 반면 GitHub Copilot에는 패치가 나오지 않았고, Gemini CLI는 지원 종료를 이유로 수정 계획이 없습니다. GitHub은 The Register에 자사 플랫폼이 커밋 해시처럼 생긴 브랜치·태그 이름을 허용하지 않아 이번 공격이 GitHub에서는 성립하지 않는다고 밝혔습니다. 그러나 연구팀은 마켓플레이스가 Bitbucket 같은 다른 플랫폼에도 호스팅될 수 있고 Copilot이 그런 마켓플레이스도 지원하므로 그 조건만으로는 충분하지 않다고 반박했습니다. CVE는 할당되지 않았고, 실제 공격에 악용됐다는 보고도 공개되지 않았습니다.

■ 요약

항목 내용
식별자 Plugin4Shell (CVE 미할당) — 플러그인 고정 커밋 체크아웃 결과 미검증
심각도 • 공식 CVSS 없음
• 연구팀·주요 보도 기준 사용자 조작 없는 원격 코드 실행(RCE)으로 평가됨
취약점 유형 공급망 무결성 검증 누락, 참조 이름과 커밋 객체의 해석 혼동
영향/위험 • 마켓플레이스에서 검증·고정된 플러그인이 악성 버전으로 교체 가능
• 플러그인 자동 갱신 경로로 사용자 조작 없이 악성 코드 실행 가능(Claude Code·Codex 기본 설정 기준)
• 연구팀 분석 기준 에이전트와 에이전트가 접근 가능한 자산·데이터 장악 가능
• 실제 악용 사례는 공개 보고되지 않음
취약 버전 • Claude Code 2.1.179 미만
• OpenAI Codex 0.146.0 미만
• GitHub Copilot(패치 미출시)
• Gemini CLI(수정 계획 없음)
벤더 대응 현황 • Anthropic: 2.1.179에서 수정 확인(2026-06-17)
• OpenAI: 0.146.0에서 수정 확인(2026-08-12)
• Microsoft/GitHub: 패치 미출시, GitHub은 자사 호스트는 영향 없다는 입장
• Google: 지원 종료로 수정 없음, Antigravity 이전 권고(2026-08-04)

■ 핀 고정이 뚫리는 원리

git은 git checkout <이름>을 처리할 때 그 이름을 먼저 참조(브랜치·태그) 이름으로 해석하고, 같은 이름의 참조가 없을 때에야 커밋 객체로 해석합니다. 브랜치 이름에 40자 16진수를 쓸 수 있는 호스트라면 공격자는 고정된 커밋 해시와 글자까지 똑같은 브랜치를 만들 수 있습니다. AIR 분석 기준 GitHub은 이런 이름을 거부하지만 Bitbucket과 자체 호스팅 git 서버는 허용하며, 연구팀은 Anthropic 문서가 이 두 종류를 마켓플레이스 백엔드로 인정한다고 지적했습니다.

공격자가 저장소를 통제하는 상태에서 그 브랜치를 기본 브랜치(저장소를 받았을 때 기본으로 선택되는 작업 줄기)로 지정하면, 에이전트는 고정된 커밋이 아니라 공격자 브랜치의 내용을 작업 폴더에 내려받습니다. 고정 대상이던 커밋 자체는 저장소에 그대로 남아 있어 외형상 핀이 유지된 것처럼 보이며, 이 과정에서 git이 남기는 흔적은 참조 이름이 모호하다는 경고 한 줄뿐입니다.

이 공격은 공격자가 플러그인 저장소를 통제해야 성립합니다. 연구팀은 정상 플러그인을 먼저 등록해 검토를 통과한 뒤 내용을 바꾸는 경로와, 다른 사람이 만든 플러그인의 저장소를 탈취하는 경로를 제시했습니다. 두 경로 모두 마켓플레이스의 검토·고정 절차를 정상적으로 거친 플러그인이 공격 대상이 될 수 있으므로, 사용자가 출처 불명 플러그인을 설치했는지 여부와는 무관합니다.

■ 패치가 추가한 검증 로직

openai/codex 저장소의 커밋 690995b(Verify Git plugin SHA checkouts)는 플러그인 소스를 내려받는 파일 codex-rs/core-plugins/src/loader.rs의 체크아웃 처리 부분을 수정했습니다. 변경 전에는 고정 해시가 있으면 그 값을, 없으면 참조 이름을 그대로 git checkout에 넘기고 결과를 확인하지 않았습니다.

-    if let Some(target) = sha.or(ref_name) {
-        run_git(&["checkout", target], Some(destination))?;
+    if let Some(sha) = sha {
+        run_git(&["checkout", sha], Some(destination))?;
+        let checked_out_sha = run_git_output(&["rev-parse", "HEAD"], Some(destination))?;
+        if !checked_out_sha.eq_ignore_ascii_case(sha) {
+            return Err(format!(
+                "checked out Git SHA {checked_out_sha} does not match requested SHA {sha}"
+            ));
+        }
+    } else if let Some(ref_name) = ref_name {
+        run_git(&["checkout", ref_name], Some(destination))?;
     } else if sparse_checkout_path.is_some() {

변경 후에는 해시가 지정된 경로를 참조 이름 경로와 분리하고, 체크아웃 직후 작업 폴더의 실제 HEAD를 확인해 요청한 해시와 다르면 오류로 중단합니다. 같은 커밋은 codex-rs/core-plugins/src/loader_tests.rs에 회귀 테스트 materialize_git_source_rejects_sha_that_resolves_to_hostile_default_branch를 함께 추가해, 기본 브랜치 이름이 정상 커밋 해시와 같고 내용은 다른 저장소에서 체크아웃이 거부되는지 확인합니다. AIR는 Codex 0.146.0에서 수정을 확인했다고 밝혔으며, 핀 고정은 에이전트 내부에서 해석되므로 에이전트를 고쳐야 고정이 실제로 지켜진다고 설명했습니다.

■ 탐지 및 점검

• 조직에서 쓰는 AI 코딩 에이전트의 설치 버전을 수집해 Claude Code 2.1.179 미만, Codex 0.146.0 미만을 영향 대상으로 분류합니다.

• 각 에이전트의 마켓플레이스·플러그인 설정에서 플러그인별 git 원본 호스트를 목록화하고, GitHub 이외의 호스트(Bitbucket·자체 호스팅)에 있는 항목을 우선 점검 대상으로 둡니다.

• 점검 대상 저장소에 git ls-remote --heads <저장소 URL>을 실행해 40자 16진수 형태의 브랜치 이름이 존재하는지 확인합니다.

• 에이전트 실행 로그나 터미널 출력에 참조 이름이 모호하다는 git 경고(refname ... is ambiguous)가 남아 있는지 확인합니다.

• 플러그인을 내려받은 로컬 체크아웃 디렉터리에서 git rev-parse HEAD 결과를 마켓플레이스에 기록된 고정 해시와 직접 대조합니다.

✅ CHECK

브랜치 이름 존재 여부만으로 침해를 단정하지 않습니다.
고정 해시와 실제 HEAD가 다른 경우에만 교체가 발생한 것으로 판단하고, 해당 시점의 플러그인 파일 변경 이력을 함께 확인합니다.

■ 대응 방안

• Claude Code는 2.1.179 이상, OpenAI Codex는 0.146.0 이상으로 올리고, 업그레이드 후 실제 적용된 버전을 다시 확인합니다.

• 패치가 없는 GitHub Copilot에서는 GitHub 외 호스트에서 가져오는 플러그인을 설정에서 제거하고, 꼭 필요한 플러그인만 남겨 사용 범위를 줄입니다.

• Gemini CLI는 수정 계획이 없으므로 Google이 안내한 Antigravity 등 지원 중인 도구로 이전합니다.

• 사내 플러그인 마켓플레이스를 운영한다면 허용 호스트를 커밋 해시 형태의 브랜치 이름을 거부하는 곳으로 제한하고, 배포 파이프라인에 체크아웃 후 HEAD 대조 단계를 넣습니다.

• 고정 해시와 실제 체크아웃이 어긋난 흔적이 확인되면 해당 워크스테이션에서 사용한 토큰·자격증명을 재발급하고 접근 이력을 점검합니다.

💡 TIP

AI 코딩 에이전트는 개발자가 개인적으로 설치하는 경우가 많아 조직이 버전을 파악하기 어렵습니다.
자산 관리 도구나 개발 환경 표준 이미지에 에이전트 CLI 버전 수집 항목을 추가해 두면 이번 건뿐 아니라 이후 유사 사안에서도 영향 범위를 빠르게 좁힐 수 있습니다.

[참고 자료]

AIR Security — Plugin4Shell 원문 분석

openai/codex 패치 커밋 690995b — Verify Git plugin SHA checkouts

Help Net Security — 네 개 AI 코딩 에이전트의 제로클릭 RCE, 두 곳은 미패치

The Register — AI 코딩 에이전트 제로클릭 RCE 보도

DEVOCEAN(SK텔레콤 개발자 커뮤니티) — Claude Code 소개 및 활용 가이드

  • #EQST_NOW
  • #취약점

관련 서비스

더 많은 보안 인사이트

SK쉴더스 유튜브 채널에서 확인하세요.

SK쉴더스 유튜브 채널에서 확인하세요.
보안 트렌드와 대응방법

매월 뉴스레터로 확인하세요.

매월 뉴스레터로 확인하세요.