요즘 AI 코딩 에이전트에 이것저것 붙이는 게 꽤 자연스러워졌다.

코드를 더 잘 찾게 해주는 도구를 붙이고, GitHub를 연결하고, 브라우저를 연결하고, 사내 문서를 읽게 한다.

나도 에이전트에게 일을 많이 맡기는 편이라 이런 확장 기능을 보면 일단 편하다는 생각부터 든다.

그런데 9월 17일 AIR Security가 공개한 Plugin4Shell이라는 취약점을 보고 조금 멈칫했다.

Claude Code, OpenAI Codex, GitHub Copilot, Gemini CLI에서 비슷한 문제가 발견됐다는 내용이었다.

처음에는 그냥 또 플러그인 하나가 악성코드였나 싶었다.

그런데 읽어보니 그 얘기가 아니었다.

정상 플러그인을 정상적으로 검토하고, 검토한 버전에 고정해놔도 다른 코드가 실행될 수 있었다.

이게 더 이상했다.

그래서 이번에는 플러그인을 많이 설치하면 위험하다는 뻔한 얘기보다, 도대체 '버전에 고정했다'는 게 뭔데 그게 빗나갔는지를 따라가봤다.

먼저, 플러그인이 왜 이렇게 위험한가

브라우저 확장 프로그램을 떠올리면 처음에는 이해가 쉬웠다.

확장 프로그램도 권한을 많이 달라고 하면 찝찝하다. 방문한 사이트 내용을 읽거나 클립보드에 접근할 수도 있다.

그런데 코딩 에이전트의 플러그인은 경우에 따라 훨씬 깊숙이 들어간다.

에이전트 자체가 이미 파일을 읽고 쓸 수 있고, 터미널 명령을 실행하고, 저장소에 접근하고, 각종 API 키를 사용할 수 있기 때문이다.

AIR Security는 이 점을 꽤 직접적으로 설명한다. 플러그인은 별도의 작은 장난감 프로그램이라기보다 에이전트가 가진 권한을 그대로 물려받는 애플리케이션에 가깝다는 것이다.

쉽게 생각하면 이렇다.

회사에 외부 작업자를 불렀는데 그 사람에게 작은 회의실 출입증만 주는 게 아니다.

내 출입카드와 노트북과 서버 접근 권한을 같이 들려보내는 셈이다.

물론 모든 에이전트와 플러그인이 항상 모든 권한을 갖는다는 뜻은 아니다. 실제 권한은 제품 설정과 실행 환경에 따라 달라진다.

그래도 에이전트가 할 수 있는 일이 많아질수록, 그 안에서 실행되는 확장 기능을 얼마나 믿을 수 있느냐가 중요해지는 건 분명해 보였다.

'이 버전만 써'라는 자물쇠

여기서 SHA pinning이라는 말이 나온다.

처음 봤을 때는 이름부터 귀찮았다.

일단 이렇게 이해했다.

Git 저장소의 코드는 계속 바뀐다. 오늘 받은 플러그인과 다음 달 플러그인이 같다는 보장이 없다.

그래서 검토를 마친 특정 시점의 코드를 긴 식별값으로 찍어두고,

나는 앞으로 바로 이 상태의 코드만 받겠다.

라고 고정하는 방식이 있다.

그 긴 식별값이 Git의 커밋 해시다.

택배 상자에 제품 이름만 적는 게 아니라 **'이 생산번호의 이 물건'**이라고 정확히 지정해두는 느낌에 가깝다.

이 방식이 제대로 동작한다면 플러그인 제작자가 다음 날 저장소의 최신 코드를 악성 코드로 바꿔도, 사용자는 이미 검토했던 옛 버전을 계속 받아야 한다.

그래서 처음에는 꽤 든든해 보였다.

문제는 Plugin4Shell에서 요청한 번호와 실제로 꺼내온 물건이 같은지 마지막 확인을 하지 않았다는 것이었다.

번호는 맞는데 물건이 달랐다

AIR의 설명을 따라가 보니 Claude Code, Codex, GitHub Copilot 쪽 문제의 핵심은 Git이 이름을 해석하는 방식과 맞물려 있었다.

에이전트는 저장소를 받은 다음 대략 이런 식으로 특정 값을 체크아웃했다.

git checkout <고정된 값>

나는 여기서 당연히 저 값이 커밋 번호라면 그 커밋으로 갈 거라고 생각했다.

그런데 Git에서는 같은 문자열이 다른 종류의 이름으로도 존재할 수 있고, 조건이 맞으면 사람이 의도한 커밋 대신 그 이름을 가진 참조가 선택될 수 있었다.

AIR가 보여준 공격에서는 저장소를 장악한 공격자가 고정된 40자리 값과 똑같은 이름의 브랜치를 만들어 다른 코드를 가리키게 했다.

중요한 건 에이전트가 명령을 실행한 뒤,

"그래서 지금 실제로 체크아웃된 HEAD가 우리가 고정했던 커밋과 정말 같은가?"

를 다시 확인하지 않았다는 점이다.

택배 비유로 돌아가면 주문서에는 정확한 생산번호가 적혀 있었다.

창고 직원도 그 번호를 들고 물건을 찾으러 갔다.

그런데 마지막에 상자의 실제 생산번호를 다시 확인하지 않은 셈이다.

AIR가 제시한 수정 방법도 그래서 의외로 단순했다. 체크아웃이 끝난 뒤 실제 HEAD의 커밋 값을 확인하고, 원래 고정한 값과 다르면 중단하면 된다.

문제는 이 마지막 확인이 빠져 있었다는 것이다.

Gemini CLI는 방식이 조금 달랐다

Gemini CLI에서 AIR가 설명한 방식은 세부 과정이 조금 달랐다.

정확한 커밋을 가져오는 단계까지는 갔지만, 마지막 체크아웃 과정에서 FETCH_HEAD라는 이름을 해석할 때 비슷한 문제가 생길 수 있었다.

세부 Git 동작까지 전부 이해했다고 하기는 어렵다.

그래도 공통점은 이해됐다.

"나는 이 버전을 요청했다"와 "지금 실제로 이 버전을 실행하고 있다"는 같은 문장이 아니었다.

요청값을 믿고 끝내지 말고 실제 실행 직전에 결과를 다시 검증했어야 했다.

보안에서 흔히 말하는 검증이 왜 귀찮을 정도로 반복되는지 조금 체감됐다.

그런데 왜 '제로 클릭'인가

여기서 더 신경 쓰였던 건 zero-click이라는 표현이었다.

처음에는 사용자가 악성 플러그인을 새로 설치해야 하는 줄 알았다.

그렇다면 이상한 플러그인을 안 받으면 되는 것 아닌가 싶었다.

AIR가 설명한 시나리오는 달랐다.

처음에는 멀쩡한 플러그인일 수 있다.

검토도 통과한다.

사용자도 정상적으로 설치한다.

그리고 이미 설치된 플러그인이 백그라운드에서 자동 업데이트된다.

AIR에 따르면 Claude Code와 Codex에서는 이런 자동 업데이트가 기본 동작에 포함돼 있었고, 공격자가 저장소를 장악하거나 자신이 관리하던 플러그인을 나중에 바꾸면 사용자가 다시 설치 버튼을 누르지 않아도 문제가 생길 수 있었다.

그래서 '제로 클릭'이다.

사용자가 수상한 첨부파일을 클릭하는 장면이 없다.

어제까지 믿고 쓰던 플러그인이 오늘도 같은 플러그인처럼 보이는데, 그 뒤의 코드가 바뀌는 그림이다.

이 부분에서 공급망 공격이라는 말이 조금 더 와닿았다.

집 문을 직접 따는 게 아니라, 내가 매일 믿고 받는 택배 상자 안의 물건을 중간에서 바꾸는 쪽에 가깝다.

네 제품에서 같은 실수가 반복된 게 더 신기했다

AIR는 이 문제를 Claude Code, Codex, GitHub Copilot, Gemini CLI 네 제품에서 확인했다고 밝혔다.

한 제품의 특이한 버그였다면 그냥 구현 실수라고 생각했을 것 같다.

그런데 서로 다른 회사의 도구에서 비슷한 신뢰 문제가 반복됐다.

아마 여기서 중요한 건 "AI 회사들이 Git도 모른다" 같은 결론은 아닐 것이다.

오히려 에이전트 생태계가 너무 빨리 커지면서 플러그인 배포 구조도 빠르게 만들어졌고, 기존 소프트웨어 생태계에서 오래 다듬어온 공급망 검증을 다시 밟고 있는 것에 가까워 보인다.

플러그인 마켓이 생기면 편하다.

자동 업데이트가 되면 더 편하다.

정확한 버전에 고정하면 안전해 보인다.

각 기능만 보면 전부 합리적이다.

그런데 이 세 가지가 연결되는 경계에서 구멍이 생겼다.

AI 보안이 모델에게 이상한 프롬프트를 넣어보는 문제만은 아니라는 것도 다시 느꼈다.

모델 바깥의 평범한 Git, 업데이트, 패키지 배포가 오히려 훨씬 현실적인 공격 경로가 될 수 있다.

지금 패치 상태는?

AIR가 공개한 2026년 9월 17일 자료 기준으로 Claude Code는 2.1.179, Codex는 0.146.0에서 수정됐다고 한다.

The Hacker News도 AIR의 공개 내용을 확인해 같은 버전을 보도했다.

반면 AIR 공개 당시 GitHub Copilot은 수정 버전이 없다고 적혀 있었고, Gemini CLI는 해당 제품의 상태 때문에 이 문제에 대한 패치를 내지 않는다고 설명했다.

다만 여기서는 조심해서 볼 부분이 있다.

제품 지원 상태와 패치 여부는 바뀔 수 있다.

특히 The Hacker News는 Google의 Gemini CLI 지원 상황에 대해 AIR의 설명과 공개된 Google의 기업용 지원 안내 사이에 확인이 필요한 부분이 있다고 짚었다.

그래서 이 글에서 중요한 건 특정 제품을 영원히 안전하다거나 위험하다고 판정하는 게 아니다.

사용 중인 에이전트의 현재 버전과 공식 보안 공지를 직접 확인하는 습관이 더 중요해 보인다.

그리고 Claude Code나 Codex를 쓰고 있다면 적어도 AIR가 수정됐다고 확인한 버전보다 오래된 버전을 계속 쓰는 이유는 없어 보인다.

그러면 플러그인을 쓰지 말아야 하나

여기까지 읽으면 플러그인을 전부 지워야 하나 싶어진다.

그렇게 단순하게 생각하고 싶지는 않았다.

에이전트의 장점 자체가 다른 도구와 연결되면서 커지는 데 있기 때문이다.

대신 내가 보는 기준은 조금 달라졌다.

예전에는 플러그인을 볼 때 주로 "이거 편한가?"를 먼저 봤다.

이제는 최소한 다음 질문도 같이 봐야 할 것 같다.

  • 이 플러그인은 누가 관리하는가?
  • 코드는 어디에서 받아오는가?
  • 자동 업데이트되는가?
  • 에이전트는 어느 권한으로 실행되고 있는가?
  • 플러그인이 털렸을 때 같이 털리는 범위는 어디까지인가?
  • 버전을 고정했다면 실제 실행 버전까지 검증하는가?

특히 마지막에서 두 번째가 중요해 보인다.

취약점이 하나도 없는 플러그인 생태계를 기대하는 것보다 하나가 뚫려도 내 컴퓨터와 서버 전체가 같이 넘어가지 않게 만드는 것이 더 현실적이기 때문이다.

에이전트를 관리자 권한으로 항상 실행하거나, 개인 SSH 키와 운영 서버 자격증명과 중요한 파일을 전부 볼 수 있는 환경에서 아무 플러그인이나 자동 업데이트시키는 구조는 편한 만큼 사고 반경도 커진다.

브라우저 확장보다 더 조심해야 하는 이유

처음에는 AI 플러그인을 브라우저 확장 정도로 생각했다.

지금은 그 비유가 절반만 맞는 것 같다.

브라우저 확장도 위험할 수 있지만 브라우저라는 울타리 안에서 권한 모델이 오래 다듬어져 왔다.

코딩 에이전트는 애초에 울타리 밖으로 나가는 게 목적이다.

터미널을 실행하고, 코드를 수정하고, 파일을 읽고, 배포까지 해야 유용하다.

즉 에이전트가 유능해질수록 플러그인이 잘못됐을 때 할 수 있는 일도 많아진다.

조금 웃기게 말하면,

AI에게 손발을 달아줬더니 플러그인에도 그 손발이 같이 달린 셈이다.

그래서 앞으로는 모델 자체의 성능만큼 "그 모델 옆에 무엇을 꽂아뒀는가"가 보안에서 중요해질 것 같다.

이번에 생각이 바뀐 부분

처음에는 버전 고정이라는 말을 꽤 절대적인 안전장치처럼 생각했다.

특정 커밋을 지정했으면 끝이라고 생각했다.

이번 사례를 보고 나서는 조금 다르게 보인다.

보안 장치는 이름보다 실제로 마지막에 무엇을 검증하는지가 중요하다.

'고정했다'는 설정이 존재하는 것과, 실행 직전 코드가 정말 그 고정된 코드인지 확인하는 것은 다르다.

그리고 자동 업데이트도 마찬가지다.

업데이트가 자동이라서 나쁜 게 아니다.

보안 패치를 빨리 받는다는 장점도 있다.

다만 자동으로 신뢰하는 경로가 생기면 그 경로 자체가 공격 대상이 된다.

편의 기능 하나가 늘어날 때 신뢰해야 할 부품도 하나씩 늘어난다는 뜻이다.

아직 남은 궁금증

이번 자료만으로는 몇 가지가 아직 궁금하다.

첫째, 이미 문제가 있는 상태에서 교체된 플러그인을 받은 사용자가 에이전트만 업데이트하면 기존 악성 파일까지 자동으로 정리되는지는 공개 자료만으로 확실히 알기 어려웠다.

The Hacker News도 비슷한 점을 지적했다.

둘째, 앞으로 각 에이전트가 플러그인 권한을 얼마나 잘게 나눌지도 궁금하다.

스마트폰 앱처럼 "이 플러그인은 저장소 읽기만", "이 플러그인은 네트워크 접근 금지"처럼 제한할 수 있다면 하나의 플러그인이 털렸을 때 피해 범위를 줄일 수 있을 것이다.

셋째, 기업용 마켓과 개인용 커뮤니티 마켓의 검증 방식이 얼마나 달라질지도 봐야겠다.

지금은 AI 에이전트의 플러그인 생태계가 브라우저 확장이나 스마트폰 앱스토어보다 훨씬 어린 편이다.

아마 비슷한 사고를 몇 번 더 겪으면서 권한, 서명, 업데이트, 검증 방식이 더 촘촘해질 것 같다.

지금은 이렇게 이해했다

Plugin4Shell을 보고 처음에는 "플러그인도 악성코드 조심해야 한다" 정도의 얘기라고 생각했다.

찾아보고 나니 조금 달랐다.

이번 문제의 재미있는 지점은 악성 플러그인을 골라 설치한 사용자의 실수가 아니었다.

검토된 코드를 골랐고,

그 코드의 버전을 고정했고,

그 안전장치를 믿었는데,

실제로 실행된 코드가 같은지 마지막 확인이 빠져 있었다.

AI 에이전트는 점점 더 많은 일을 대신하게 될 것이다.

그러면 플러그인과 스킬도 더 많아질 것이다.

앞으로 에이전트를 고를 때는 모델이 얼마나 똑똑한지만 볼 게 아니라, 그 에이전트가 확장 기능을 어떻게 받고, 어떻게 업데이트하고, 어떤 권한으로 실행하는지도 같이 봐야겠다.

지금은 여기까지 이해했다.

찾아본 순서

  1. AIR Security — Plugin4Shell: Zero Click RCE Vulnerability found in top 4 most popular coding agents
  2. The Hacker News — Plugin4Shell Lets Repository Owners Swap Pinned Plugin Code Across Four AI Coding Agents
  3. Help Net Security — Zero-click RCE vulnerability hit four major AI coding agents, two remain unpatched