Plugin4Shell 대응 가이드: AI 코딩 에이전트 플러그인 점검과 패치
AI 코딩 에이전트의 플러그인은 단순한 프롬프트 묶음이 아니다. 훅, 실행 파일, MCP 서버, 셸 명령을 포함해 사용자의 파일과 자격증명에 접근할 수 있다. 2026년 9월 17일 AIR Security가 공개한 Plugin4Shell은 이 배포 경로의 핵심 안전장치인 커밋 SHA 고정을 우회한다. 검토한 커밋을 지정했는데도 공격자가 다른 코드를 설치하게 만들 수 있고, 백그라운드 자동 업데이트가 켜져 있으면 이미 설치한 플러그인도 사용자 조작 없이 바뀔 수 있다는 내용이다.
이 글의 목적은 공격 코드를 재현하는 것이 아니라, 지금 설치된 에이전트와 플러그인을 어떻게 확인하고 패치하며 권한을 줄일지 정리하는 것이다. AIR의 공개 내용과 OpenAI·Anthropic의 플러그인 문서를 2026년 9월 20일 확인했다. 현재 버전은 이미 패치 기준보다 높을 수 있으므로 아래 숫자는 “최소 안전 기준”으로 읽고, 실제 설치 버전과 최신 안정판을 함께 확인해야 한다.
핵심 요약: 먼저 버전, 그다음 플러그인
- Claude Code: AIR에 따르면 2.1.179에서 수정됐다.
claude --version으로 확인하고 그 미만이면 즉시 업데이트한다. - OpenAI Codex: AIR와 공개 수정 PR에 따르면 0.146.0에서 해결됐다.
codex --version으로 확인하고 설치 방식에 맞춰 최신 안정판으로 올린다. - GitHub Copilot: AIR 공개 시점에는 수정판이 없었다. 비필수 마켓플레이스 플러그인을 중지하고 공급자 공지를 확인해야 한다.
- Gemini CLI: AIR는 해당 도구가 패치되지 않으며 후속 환경으로 이전하라고 설명한다. 남아 있는 설치와 자동 실행 경로를 우선 분리한다.
- 공통: 패치만으로 과거 노출 여부를 알 수는 없다. 설치 목록, 업데이트 기록, 비밀정보 접근 흔적도 함께 검토한다.
Plugin4Shell은 무엇을 우회했나
마켓플레이스는 보통 플러그인 저장소의 특정 커밋 SHA를 기록한다. 검토 당시의 코드를 정확히 가리키는 긴 식별자이므로, 저장소의 최신 코드가 나중에 바뀌더라도 같은 내용이 설치될 것이라고 기대한다. 문제는 일부 에이전트가 요청한 SHA로 체크아웃을 시도한 뒤, 실제 작업 트리의 HEAD가 그 커밋과 같은지 다시 확인하지 않았다는 점이다.
Claude Code, Codex, Copilot에서 설명된 방식은 공격자가 저장소의 기본 브랜치 이름을 고정된 SHA와 똑같이 만드는 것이다. Git은 모호한 이름에서 커밋 객체보다 참조 이름을 우선할 수 있어, 화면에는 고정값이 유지된 것처럼 보이면서 실제로는 공격자 브랜치가 체크아웃될 수 있다. GitHub는 40자리 16진수 브랜치 이름을 막지만 Bitbucket과 일부 자체 호스팅 Git은 허용할 수 있다. 따라서 “모든 기본 GitHub 플러그인이 즉시 감염됐다”는 뜻은 아니며, 저장소 호스트와 배포 방식이 노출 조건을 결정한다.
Gemini CLI에는 별도의 FETCH_HEAD 이름 충돌 방식이 보고됐다. 공통 원인은 같다. 요청한 이름만 믿고 설치 뒤의 실제 커밋을 검증하지 않은 것이다. OpenAI의 수정 PR은 체크아웃 후 HEAD를 해석하고 요청한 SHA와 정확히 같지 않으면 플러그인 소스를 거부하도록 바꿨다.

영향 범위를 판단하는 네 가지 질문
- 마켓플레이스 플러그인을 설치했는가? 프로젝트 폴더의 로컬 설정만 쓰고 외부 마켓플레이스를 전혀 쓰지 않았다면 이 취약점의 직접 노출 범위가 줄어든다.
- 플러그인 원본이 어디에 있는가? GitHub, GitLab, Bitbucket, 자체 Git 서버, URL 배포 등 출처를 구분한다. SHA처럼 보이는 브랜치 이름을 허용하는 호스트가 더 위험하다.
- 자동 업데이트가 켜져 있는가? AIR는 Claude Code와 Codex의 백그라운드 업데이트 때문에 기존 설치에도 사용자 클릭 없이 변경이 도달할 수 있다고 설명한다.
- 플러그인이 무엇을 실행하는가? 스킬 설명만 제공하는 플러그인과 훅·바이너리·MCP 서버·셸 명령을 포함한 플러그인의 잠재 피해 범위는 다르다.
15분 안에 할 1차 대응
1단계, 에이전트를 종료한다. 의심스러운 플러그인이 로드된 세션과 백그라운드 작업을 먼저 멈춘다. 아직 원인을 모르는 상태에서 업데이트나 재실행을 반복하면 로그가 바뀌거나 외부 연결이 이어질 수 있다.
2단계, 버전을 기록한다. 터미널에서 claude --version과 codex --version을 실행해 결과를 복사한다. 팀 장비라면 운영체제, 설치 방식, 실행 시각도 함께 적는다. 패치 후 비교할 기준이 된다.
3단계, 설치 플러그인을 목록화한다. Claude Code에서는 /plugin의 Installed 탭 또는 /plugin list를 사용하고, 각 항목의 상세 화면에서 스킬·에이전트·훅·MCP 서버·LSP 서버를 확인한다. Codex와 ChatGPT에서는 Plugins의 Installed 목록에서 설치 주체, 연결된 MCP, 훅과 브라우저 기능을 확인한다.
4단계, 비필수 항목을 비활성화한다. Claude Code에서는 /plugin disable 플러그인명@마켓플레이스명으로 중지할 수 있다. 출처를 설명할 수 없거나 최근 사용하지 않은 항목, 자체 호스팅 Git에서 가져오는 항목부터 격리한다. 관리자가 강제 설치한 플러그인은 임의 제거보다 관리자에게 목록과 버전을 전달한다.
5단계, 네트워크와 비밀정보를 보호한다. 의심이 있으면 해당 장비에서 클라우드 자격증명, 패키지 레지스트리 토큰, Git 토큰, SSH 키의 사용을 일시 중지한다. 단순히 플러그인을 지우는 것으로 이미 노출된 비밀정보가 무효화되지는 않는다.
패치와 완료 확인
| 도구 | 최소 수정 기준 | 확인 방법 | 패치가 없을 때 |
|---|---|---|---|
| Claude Code | 2.1.179 | claude --version, 설치 방식에 맞춰 최신판 업데이트 후 재확인 | 해당 없음. 지원되는 최신 안정판 사용 |
| Codex | 0.146.0 | codex --version, 원래 설치 경로로 최신판 업데이트 후 재확인 | 해당 없음. 지원되는 최신 안정판 사용 |
| GitHub Copilot | AIR 공개 시점 미제공 | 공급자 보안 공지와 플러그인 관리 화면 확인 | 마켓플레이스 플러그인 중지, 최소 권한 환경에서만 사용 |
| Gemini CLI | AIR 공개 시점 패치 계획 없음 | 남은 설치·자동 실행·플러그인 경로 확인 | 이전 계획 수립, 기존 실행 환경 격리 |
완료 기준은 업데이트 명령이 끝났다는 메시지가 아니다. 새 터미널에서 버전이 기준 이상인지 확인하고, 플러그인 목록을 다시 열어 비활성화 상태와 출처가 유지되는지 확인해야 한다. Claude Code에서 외부 명령으로 변경했다면 세션에서 /reload-plugins를 실행하거나 새 세션을 시작한다.

이미 실행됐을 가능성이 있을 때의 조사 순서
취약한 버전이었다고 해서 곧바로 침해가 확정되는 것은 아니다. 반대로 업데이트했다고 과거 실행이 사라지는 것도 아니다. 먼저 설치된 플러그인의 저장소 URL, 마켓플레이스 이름, 고정 SHA, 마지막 업데이트 시각을 보존한다. 그다음 플러그인 폴더에서 예상하지 못한 실행 파일, 훅, MCP 설정, 최근 변경 파일을 찾는다. 플러그인 자체를 실행해 “안전한지 시험”하지 말고 정적 목록과 로그부터 확인한다.
이후 에이전트가 접근할 수 있었던 범위를 그린다. 프로젝트 파일만 읽었는지, 홈 디렉터리와 SSH 키에 접근 가능했는지, GitHub·클라우드·배포 플랫폼 토큰이 환경 변수에 있었는지, 브라우저나 MCP를 통해 외부 서비스에 연결됐는지 구분한다. 의심 정황이 있으면 관련 토큰을 폐기하고 새로 발급하며, 최근 커밋·릴리스·패키지 게시·클라우드 감사 로그를 검토한다. 개인 장비보다 조직 장비는 보안 담당자와 함께 증거 보존 절차를 따르는 편이 안전하다.
세 가지 실제 운영 시나리오
개인 개발자: 커뮤니티 플러그인 몇 개를 설치한 경우
목표는 빠르게 사용 목록을 줄이는 것이다. 버전을 패치한 뒤 Installed 목록에서 최근 30일간 실제로 쓴 항목만 남긴다. 각 플러그인의 원본 저장소와 마켓플레이스가 설명되지 않으면 비활성화한다. 개인 Git 토큰이 에이전트 셸에 노출돼 있었다면 토큰 사용 기록을 확인하고 이상 징후가 있을 때 교체한다.
팀 저장소: 프로젝트 설정으로 플러그인을 공유하는 경우
목표는 팀원마다 다른 상태를 없애는 것이다. 저장소의 .claude/settings.json 같은 공유 설정에서 마켓플레이스와 활성 플러그인을 추출하고, 허용 목록을 만든다. 최소 버전을 CI나 장비 관리 정책에 기록하고, 플러그인의 저장소 호스트·소유자·검토 SHA·권한을 변경 승인 항목으로 관리한다. 완료 기준은 모든 팀원의 버전과 설치 목록이 같은 정책을 만족하는 것이다.
조직 관리자: 자체 마켓플레이스를 운영하는 경우
목표는 “검토했으니 안전하다”는 단일 가정을 없애는 것이다. 저장소 호스트가 SHA 모양의 브랜치 이름을 허용하는지 확인하고, 배포 클라이언트가 체크아웃 뒤 실제 HEAD를 비교하는지 검증한다. 마켓플레이스 심사, 고정 SHA, 서명, 실행 권한, 네트워크 제한, 비밀정보 격리를 서로 독립된 통제로 둔다. 하나가 실패해도 전체 장비 권한까지 이어지지 않도록 해야 한다.
SHA 고정만으로 부족한 이유
SHA 고정은 여전히 필요하다. 하지만 Plugin4Shell은 “고정값을 기록하는 것”과 “그 값의 코드를 실제로 실행하는 것”이 다른 단계임을 보여준다. 안전한 배포에는 체크아웃 뒤 커밋 재검증, 플러그인 출처의 소유권 확인, 자동 업데이트 정책, 실행 구성 요소 공개, 최소 권한, 비밀정보 분리, 로그와 롤백이 함께 필요하다.
또한 플러그인 지침은 접근 제어가 아니다. 앞서 다룬 Claude Code 플러그인 패키징 가이드처럼 플러그인은 훅과 MCP 서버까지 묶을 수 있다. “이 파일은 읽지 말라”는 문장보다 샌드박스, 운영체제 권한, 네트워크 허용 목록, 짧은 수명의 토큰이 실제 방어선이다.
자주 막히는 상황
- 버전은 최신인데 기준 숫자보다 낮게 보임: 여러 설치본이 PATH에 섞였을 수 있다.
which claude또는which codex로 실제 실행 파일 위치를 확인하고 원래 설치 관리자로 업데이트한다. - 플러그인을 껐는데 현재 세션에서 계속 보임:
/reload-plugins를 실행하거나 새 세션을 시작한다. MCP 서버 변경은 환경에 따라 다음 세션에서 적용될 수 있다. - 관리형 플러그인을 제거할 수 없음: 조직 정책이 강제한 항목일 수 있다. 이름, 버전, 출처, 오류 화면을 관리자에게 전달하고 개인 설정으로 우회하지 않는다.
- 감염 여부를 판단할 로그가 없음: 무조건 안전하다고 결론내리지 않는다. 접근 가능한 자격증명부터 범위를 줄이고 중요한 토큰을 교체한 뒤, 향후 플러그인 업데이트와 실행 로그를 보존하도록 정책을 바꾼다.
최종 체크리스트
- Claude Code 2.1.179 이상, Codex 0.146.0 이상인지 새 터미널에서 확인했다.
- 설치된 플러그인과 마켓플레이스 출처를 목록화했다.
- 비필수·미사용·출처 불명 플러그인을 비활성화했다.
- 훅, 실행 파일, MCP 서버, 네트워크 연결을 별도로 검토했다.
- 의심 장비가 접근할 수 있었던 토큰과 비밀정보의 사용 기록을 확인했다.
- 조직 정책에 최소 버전, 허용 마켓플레이스, 업데이트·롤백 절차를 반영했다.
Plugin4Shell의 교훈은 플러그인을 쓰지 말라는 것이 아니다. 에이전트 플러그인은 코드와 권한을 전달하는 소프트웨어 공급망이므로, 프롬프트 파일보다 패키지 관리자에 가까운 기준으로 관리해야 한다는 것이다.
English version: Plugin4Shell Response Guide: Audit and Patch AI Coding-Agent Plugins
공식·원문 자료
- AIR Security: Plugin4Shell 기술 공개 (2026-09-20 확인)
- OpenAI Codex PR: Verify Git plugin SHA checkouts (2026-09-20 확인)
- Anthropic: Discover and install plugins (2026-09-20 확인)
- OpenAI: Plugins in ChatGPT and Codex (2026-09-20 확인)
댓글
댓글 쓰기