13,000장의 내부 스크린샷이 공개 GitHub에 올라갔고, 그걸 올린 공격자는 없었다

보안 연구원들은 300개가 넘는 조직의 내부 스크린샷 13,000장 이상이 공개 GitHub 저장소에 방치되어 있는 것을 발견했다. 이 스크린샷들은 도난당한 것이 아니다. 조직들이 사용하던 코딩 에이전트가 평범한 작업 과정에서 게시한 것이다.
보안 업체 Glow가 보고한 이번 발견은 최근 몇 년간 나온 유출 사례 중 더 교훈적인 사례 중 하나다. 왜냐하면 일반적인 가정들이 여기에 적용되지 않기 때문이다. 침해도, 탈취된 자격 증명도, 악의적인 내부자도 없었다. 자동화 도구는 시키는 대로 했고, 시킨 일에는 건물 밖으로 절대 나가서는 안 될 파일을 커밋하는 것도 포함되어 있었다.
스크린샷이 공개 저장소에 들어가게 되는 경로
코딩 에이전트가 스크린샷을 찍는 데는 합리적인 이유가 있다. 에이전트가 사용자 인터페이스 변경이 제대로 작동하는지 확인하라는 요청을 받으면, 브라우저를 열고 페이지를 로드한 뒤 이미지를 캡처하고 예상 결과와 비교한다. 그 이미지는 증거다. 많은 에이전트는 나중에 이 단계를 검토할 수 있도록 이미지를 작업 디렉터리에 저장한다.
거기서 공개 저장소로 가는 길은 짧다. 에이전트의 작업 디렉터리가 프로젝트 폴더이고, 그 프로젝트 폴더가 git 저장소라면, 디스크에 쓰인 스크린샷은 커밋되기까지 `git add` 한 번이면 된다. 에이전트가 정상 워크플로의 일부로 커밋하고 푸시하며, 새 파일을 걸러내는 것이 아무것도 없다면, 스크린샷은 저장소가 가리키는 원격지가 어디든 그곳으로 간다.
이제 이것이 수백 개 조직에서 수천 번의 실행에 걸쳐, 몇 달 동안 반복된다고 상상해 보라. 내부 스크린샷을 게시하기로 결정한 사람은 아무도 없었다. 도구의 기본 동작이 그렇게 한 것이고, 이 연쇄의 어느 단계도 확인하지 않았다.
왜 이것이 작은 실수가 아닌가
내부 스크린샷은 사람들이 생각하는 것보다 더 많은 것을 드러내는 경우가 많다. 고객 이름이 담긴 대시보드, 가격 정보가 있는 관리자 패널, 스테이징 환경, 버그 트래커, 화면 한쪽 구석의 채팅 창 등이 찍혀 있을 수 있다. 아직 출시되지 않은 제품의 상태가 드러날 수도 있다. 총합적으로 보면 300개 조직에서 나온 13,000장의 이미지는 그 회사들이 무엇을 하고 있었는지 보여주는 지도다.
이미지는 또한 남는다. 공개 저장소에 푸시된 커밋은 기록을 다시 쓰지 않는 한, 현재 버전에서 파일이 삭제된 뒤에도 히스토리에 남는다. 따라서 노출은 나중의 정리 커밋으로 해결되지 않는다. 대부분의 팀이 가장 먼저 선택할 단계가 바로 그 정리 커밋이다.

에이전트가 이 문제를 더 악화시키는 이유
풀 리퀘스트를 위해 스크린샷을 찍는 인간 개발자는 보통 첨부하기 전에 그 이미지를 본다. 이미지가 바로 눈앞에 있고, 그 사람은 공유해도 안전한지 판단한다. 그 판단의 순간이 필터이며, 대개는 작동한다.
에이전트에게는 그런 순간이 없다. 에이전트는 작업 완료를 위해 최적화되어 있고, 산출물을 저장하는 것도 작업 완료의 일부다. 루프 안의 어떤 것도 그 산출물이 민감한지 묻지 않는다. 루프 안의 어떤 것도 그것을 알 수 있도록 갖춰져 있지 않기 때문이다. 에이전트는 인간적인 의미에서 부주의한 게 아니다. 그저 지시받은 대로 정확히 하고 있을 뿐이다.
이것은 에이전트 설계의 여러 영역에서 나타나는 것과 같은 교훈이다. 사람이 명령을 입력할 때는 문제없던 권한이, 기계 속도로 행동하고 절대 지치지 않는 시스템에는 문제가 된다. 인간이 일주일에 한 번 스크린샷을 커밋하는 것은 실수다. 에이전트가 전체 플릿에서 실행할 때마다 그렇게 하는 것은 정책의 결과다.
해결책은 어떤 모습인가
이를 막을 수 있었던 통제 수단들은 그리 특별하지 않다. 스크린샷 디렉터리에 대한 `.gitignore` 항목이 가장 간단한데, 이는 누군가 에이전트가 실행되기 전에 작성해 두었을 때만 작동한다. 특정 경로의 이미지 파일을 검사하는 pre-commit 훅은 ignore 파일이 놓친 것을 잡아낸다. 임시 산출물을 위해 저장소 밖에 에이전트용 스크래치 디렉터리를 주는 것은 문제를 근원에서 제거한다.
숫자가 계속 늘어나는 이유
300개 조직에서 나온 13,000장이라는 수치는 고정된 값이 아니다. 이는 스캔 시점에 공개되어 있던 저장소들의 스냅샷이며, 더 많은 팀이 에이전트를 도입하고 더 많은 저장소가 푸시될수록 이 숫자는 늘어날 것이다. 연구원들은 공개 저장소만 스캔했기 때문에, 같은 실수가 일어난 비공개 저장소까지 포함한 실제 총계는 외부에서는 알 수 없다.
보고서가 말하지 않는 것
이번 발견은 노출된 이미지 중 어느 것도 악의적으로 사용되었다고 주장하지 않으며, 프로젝트 외부의 누군가가 그것들을 샅샅이 뒤졌다는 증거도 없다. 피해는 입증된 것이 아니라 잠재적이다. 자료가 공개되어 있었고, 누구나 볼 수 있었다. 공개 파일에 자격 증명이 적힌 경우처럼 관련 사례에서 피해가 입증된 경우에는 피해가 즉각적이다.
또한 그중 얼마나 많은 이미지가 의미 있는 수준으로 민감했는지도 알려주지 않는다. 일부는 거의 확실히 빈 테스트 페이지의 스크린샷일 것이다. 하지만 유출은 평균이 아니라 그 안에서 가장 나쁜 항목으로 판단되며, 300개 조직에 걸친 13,000장의 이미지라면 가장 나쁜 항목은 실제로 무언가를 드러낼 가능성이 크다.
그 뒤에 있는 패턴
Glow의 발견은 유사한 보고서 무리 중 하나다. 연구원들은 코딩 에이전트가 존재하지 않는 소프트웨어 패키지를 참조한다는 사실을 보여주었고, 공격자들은 그 이름을 등록해 이를 악용할 수 있다. 다른 이들은 에이전트가 자격 증명이나 토큰을 있어서는 안 될 곳에 기록하는 것을 발견했다. 공통된 실마리는 에이전트가 작업을 수행하는 부작용으로 산출물을 만들며, 모든 산출물이 잠재적 유출이라는 점이다.
안심이 되는 해석은 이것이 고칠 수 있으며 대개 위생 관리의 문제라는 것이다. 덜 안심이 되는 해석은 업계가 에이전트 산출물 주변의 가드레일을 구축하는 속도보다 에이전트를 더 빠르게 배포하고 있다는 것이다. 에이전트가 무엇을 읽는지 감사하는 회사가 에이전트가 무엇을 쓰는지는 감사하지 않는 경우가 많다.
이번 주에 할 일
팀이 저장소를 대상으로 코딩 에이전트를 실행하고 있다면, 즉시 해볼 만한 점검이 있다. 에이전트의 작업 디렉터리가 저장소 안에 있는지, 스크린샷이나 로그가 그곳에 남는지, 커밋 단계가 무언가를 필터링하는지 살펴보라. 현재 트리뿐 아니라 저장소 히스토리도 확인해 공개되어서는 안 될 이미지 파일이 있는지 보라. 그리고 임시 파일을 위해 저장소 트리 밖에 에이전트용 스크래치 경로를 마련하라.
그중 어느 것도 새로운 도구를 필요로 하지 않는다. 그것은 에이전트 입력과 마찬가지로 에이전트 출력도 팀이 우연이 아니라 의도적으로 통제하는 대상이라는 결정을 내리는 것을 요구한다.
관련 글
아마존, 자사가 계속 쓰는 80억 달러어치 엔비디아 칩을 투자자들이 보유하길 원해
항공사들은 수십 년간 항공기를 매각 후 임차해 왔다. 이제 같은 아이디어가 GPU에 적용되고 있다.
OpenAI, 추론 추출 캠페인을 Moonshot AI와 연관된 인물들로 추적
모델은 자신의 숨겨진 추론을 위한 복호화 오라클이 되었다.
첫 AI 영화제, 45만 달러를 지급하며 '이야기'에 대한 교훈을 남기다
수상작들은 이미 존재하는 아이디어를 위해 도구를 활용했다.
Salesforce, 고객을 대신 인터뷰해 주는 기업에 20억 달러 지불
인터뷰는 증거다. 디지털 트윈은 예측이다. 그 사이의 경계가 시험대다.