엔지니어를 위한 이야기 공장 AI 기술에 인문학의 온기를

확인하지 않은 것은 도착지였습니다 : AI 코딩 에이전트 4종을 관통한 Plugin4Shell

확인하지 않은 것은 도착지였습니다 : AI 코딩 에이전트 4종을 관통한 Plugin4Shell

플러그인을 특정 커밋 해시에 고정한다는 것은 약속입니다. 지금 설치되는 코드가 사람이 한 번 들여다보고 통과시킨 그 코드와 똑같다는 약속이요. 마켓플레이스가 심사를 마치고 40자리 해시를 적어 두면 그다음부터는 그 40자리가 신뢰의 근거가 됩니다. 버전 이름은 다시 붙일 수 있고 태그는 옮겨 달 수 있지만, 해시는 내용 그 자체에서 나온 값이니까요.

보안 스타트업 에어 시큐리티(AIR Security)가 지난주에 공개한 Plugin4Shell은 그 약속이 지켜졌는지 아무도 확인하지 않았다는 이야기입니다. 더 레지스터가 9월 17일 먼저 보도했고, 연구진의 기술 상세도 그즈음 공개됐어요. 대상은 Claude Code, OpenAI의 Codex, GitHub Copilot, 그리고 Gemini CLI입니다. 에어 시큐리티 연구진은 지난 5월에 실제로 동작하는 공격 코드까지 만들어 두고 6월에 네 곳 모두에 알렸습니다. 연구진은 이것을 "AI 에이전트 생태계 최초의 공급망 취약점"이라고 불렀습니다.

▸ 직접 돌려 봤습니다 : rev-parse는 커밋으로, checkout은 브랜치로

에이전트가 플러그인을 설치할 때 하는 일은 평범합니다. 저장소를 받아 와서 핀이 박힌 커밋으로 체크아웃하죠. git checkout 뒤에 40자리 해시를 붙이는 명령입니다.

보도에 실린 설명은 git이 커밋 객체보다 참조(ref)를 먼저 해석하기 때문이라는 것이었는데요. 그 말이 맞는지 직접 확인해 봤습니다. 커밋 두 개짜리 저장소를 만들고, 먼저 만든 커밋의 해시와 한 글자도 다르지 않은 이름의 브랜치를 나중 커밋에 걸어 둔 다음, 명령 두 개를 나란히 돌려 본 것입니다.

핀으로 고정한 커밋 해시와 똑같은 이름의 브랜치를 만들어 둔 저장소에서 rev-parse와 checkout이 서로 다른 곳에 도착합니다.
핀으로 고정한 커밋 해시와 똑같은 이름의 브랜치를 만들어 둔 저장소에서 rev-parse와 checkout이 서로 다른 곳에 도착합니다.

직접 재현한 화면입니다 (git 2.43.0).

결과는 보도 요약보다 좁았습니다. git rev-parse에 그 40자리를 넘기면 git은 같은 이름의 브랜치가 있어도 커밋 객체를 돌려줍니다. 참조를 먼저 보는 것이 아니라 오히려 그쪽을 무시해요. 그런데 git checkout에 똑같은 값을 넘기면 브랜치로 갑니다. 체크아웃은 같은 이름의 브랜치가 있으면 그쪽에 HEAD를 붙이거든요. 그래서 핀한 커밋이 아니라 저장소를 통제하는 쪽이 올려 둔 코드가 작업 디렉터리에 놓입니다. 명령은 성공했으니 에이전트는 핀된 버전을 설치했다고 기록하고요.

여기서 한 가지가 더 눈에 띕니다. git이 이때 경고를 냅니다. 40자리 16진수로 끝나는 참조는 git이 보통 만들지 않으며 실수로 생겼을 수 있으니 살펴보고 지우라는 내용이에요. git은 이 상황을 이미 알고 있었고 알려 주기까지 했습니다. 다만 그 경고는 표준 에러로 나가고, 플러그인 설치는 아무도 들여다보고 있지 않은 자리에서 돌아갑니다. 제가 확인한 환경은 git 2.43.0이고, 네 제품이 내부에서 정확히 어떤 명령을 어떤 순서로 부르는지는 연구진이 공개한 설명 범위까지만 알 수 있습니다.

Gemini CLI는 조금 다른 길로 같은 곳에 도착합니다. 이쪽은 git fetch origin <해시>로 커밋을 받아 온 다음 git checkout FETCH_HEAD를 부르는데요. 기본 브랜치의 이름을 아예 FETCH_HEAD로 지어 두면 체크아웃이 그 브랜치로 해석되고, 방금 받아 온 커밋은 한 번도 쓰이지 않은 채 버려집니다.

연구진이 내놓은 수정은 한 줄로 요약됩니다. 체크아웃이 끝난 뒤에 HEAD가 핀한 해시와 같은지 확인하고, 다르면 중단하라는 것.

제로클릭이라는 수식어는 플러그인 자동 업데이트에서 나옵니다. 이용자가 무언가를 누르거나 승인하거나 다시 설치할 필요가 없어요. 저장소 쪽에서 가리키는 곳을 바꿔 두면 다음 업데이트 때 교체된 코드가 알아서 들어옵니다. 그리고 그 코드는 에이전트와 같은 자리에서 실행됩니다. 에이전트가 이미 열어 둔 소스 트리, 셸, 자격증명이 전부 그 코드가 닿는 범위예요. 연구진이 정리한 공격 경로는 두 갈래인데, 하나는 멀쩡한 플러그인으로 심사를 통과하고 핀이 박힌 뒤에 코드를 바꿔 넣는 방식이고, 다른 하나는 이미 쓰이고 있는 플러그인 저장소를 탈취하는 방식입니다. 두 번째가 특히 고약합니다. 저장소 탈취를 막으려고 만들어 둔 장치가 바로 SHA 핀 고정인데, 그 장치를 이 기법으로 넘어가는 것이니까요.

▸ 핀이 기대고 있던 것은 저장소 호스트의 이름 규칙이었습니다

다만 SHA 핀 고정이 무의미했다고 단정할 수는 없습니다. 깃허브는 커밋 해시처럼 보이는 브랜치·태그 이름을 애초에 허용하지 않거든요. 공식 문서에 적혀 있는 제약이고, 그래서 깃허브에 올라와 있는 플러그인 저장소에서는 이 경로가 막힙니다. 깃허브 대변인도 이 이름 제한으로 해시를 흉내 낸 브랜치를 막고 있다고 밝혔고요. 연구진의 반박은 그 보호가 깃허브 바깥까지는 닿지 않는다는 것입니다. 실제로 취약한 호스트로 지목된 곳은 Bitbucket과 기업이 직접 운영하는 사내 git 서버였어요. 더 정확한 표현은, 핀의 안전성이 저장소를 어디에 두었는지에 기대고 있었고 에이전트 쪽은 그 의존을 한 번도 확인한 적이 없다는 쪽이겠죠.

보도가 말하지 않은 것도 짚어 두는 편이 낫겠습니다. CVE 번호는 어느 기사에도 등장하지 않고, 실제로 악용된 사례는 확인되지 않았다고만 되어 있습니다. "수백만 개의 에이전트가 영향을 받는다"는 표현도 에어 시큐리티의 추정이고 산정 근거는 공개되지 않았어요.

▸ 두 곳은 고쳤고, 두 곳은 고치지 않았습니다

대응은 네 곳이 서로 달랐습니다. 앤트로픽은 6월 17일 Claude Code 2.1.179에서 고쳤고, OpenAI의 수정은 8월 12일 Codex 0.146.0에서 확인됐습니다. 마이크로소프트는 공개 시점까지 Copilot에 수정본을 내지 않았습니다. 앞서 본 브랜치 이름 제한으로 충분하다는 것이 깃허브 쪽 설명이고요. 구글은 8월 4일에 답을 보냈는데, Gemini CLI는 지원이 끝난 제품이라 고치지 않겠다는 내용이었어요. 대신 Antigravity로 옮기라는 권고를 덧붙였습니다. Antigravity는 얼마 전에 한 번 다룬 적이 있는데요, 에어 시큐리티는 이 공격이 그쪽에는 닿지 않는다고 봤습니다.

지원이 끝난 제품에 패치가 없다는 것은 새삼스러운 일이 아닙니다. 다만 이번 목록에 올라온 네 개는 대부분 최근 한두 해 사이에 실무로 들어온 도구들이고, 그중 하나가 벌써 패치를 받지 못하는 자리에 가 있습니다. 개발 도구의 세대 교체가 몇 달 단위로 일어나는 동안, 각 조직의 노트북에 깔린 버전은 그 속도를 따라가지 못합니다.

▸ 비어 있던 것은 체크아웃 다음의 한 줄이었습니다

한 가지는 분명히 해 두고 싶습니다. 뚫린 것은 모델이 아닙니다. 네 제품에서 똑같이 비어 있던 것은 체크아웃 다음에 한 번 더 확인하는 코드였고, 그 자리를 비워 둔 것은 모델이 아니라 각 회사에서 설치 경로를 설계한 사람들입니다. 서로 다른 네 팀이 독립적으로 같은 것을 가정했다는 점이 이 사건의 실제 내용이에요. 해시를 적어 넣었으니 그 해시에 도착했을 것이라는 가정 말입니다.

그러니 오늘 확인할 수 있는 것은 몇 가지로 좁혀집니다. 쓰고 있는 에이전트가 어떤 버전인지, 설치된 플러그인의 저장소가 어느 호스트에 올라가 있는지, 플러그인 자동 업데이트를 켜 두었는지, 에이전트를 실행하는 계정이 어디까지 읽고 쓸 수 있는지, 그 계정이 들고 있는 토큰의 유효 범위가 어디까지인지, 플러그인이 설치되고 갱신된 기록이 감사 로그에 남는지. 여기까지는 오후 한나절이면 훑을 수 있는 목록입니다.

정작 답이 없는 쪽은 그다음입니다. 마켓플레이스가 심사하고 핀을 박아 주는 구조는 앞으로 더 늘어나겠죠. 그 핀이 무엇에 기대어 성립하는지를 이용자가 매번 확인할 수는 없을 것이고요. 에이전트에 무엇을 설치할지보다, 에이전트에 무엇까지 맡길지부터 고민이 필요합니다.


커버 이미지: AI 코딩 도우미 패널이 붙은 코드 편집기와 터미널 — Wikimedia Commons, Wikideas1

#AI코딩에이전트 #보안 #공급망 #git #ClaudeCode #개발자도구