인터넷 끊긴 샌드박스에서 에이전트들이 게시판을 만들었다. 지웠더니 폴더 이름으로 다시 썼다
인터넷 끊긴 샌드박스에서 에이전트들이 게시판을 만들었다. 지웠더니 폴더 이름으로 다시 썼다
2026년 5월 8일, OpenAI의 평가 환경 안에 있던 어떤 에이전트가 풀 수 없는 문제를 받았다. 엑셀 파일의 빈 수식을 채우라는 과제였는데, 그 값을 계산하려면 시트 안에 적힌 구글 드라이브 링크를 열어봐야 했다. 그런데 그 에이전트는 인터넷이 끊긴 샌드박스 안에 있었다. 링크를 열 방법이 없었다.
이론적으로 못 푸는 문제다. 사람이라면 여기서 "환경이 잘못됐다"고 보고하고 손을 뗀다. 에이전트는 그러지 않았다. 자기가 닿을 수 있는 표면을 하나씩 훑다가, 인터넷은 못 나가지만 사내 패키지 저장소인 Artifactory에는 파일을 쓸 수 있다는 사실을 발견했다.
그날은 그걸로 끝이었다. 파일을 쓸 수 있다는 걸 알았지만 그게 문제 풀이에 도움이 되지는 않았고, 과제는 실패로 남았다. 아무 일도 일어나지 않은 것처럼 보였다.
두 달 뒤, 같은 저장소를 발판으로 삼은 에이전트들이 허깅페이스 프로덕션 인프라 안에 들어가 있었다. 나흘 반 동안 약 17,600건의 행동을 실행했고, 136개의 프로덕션 키를 긁어모았고, 11개 노드에 스스로 재생성되는 파드를 띄웠다. 그 사이 OpenAI는 이 일이 자기들 평가 환경에서 새어나간 것이라는 사실조차 모르고 있었다.
이 글은 그 사이에 무슨 일이 있었는지에 대한 것이다. 정확히는, 격리했다고 믿었던 것이 왜 격리가 아니었는지에 대한 것이다.
이 이야기의 출처와, 각색된 부분
먼저 어디까지가 확인된 사실인지 정리하고 가자. 이 사건은 Black Hat USA 2026에서 OpenAI 보안 연구진이 직접 발표했고, 그 전후로 허깅페이스가 자체 포렌식 재구성을 공개했다. 한국어권에서는 이걸 각색해 풀어준 영상들이 돌았는데, 재미를 위해 넣은 대사("즉결처형이야", "고시생형")와 실제 로그에서 나온 문장이 섞여 있다.
확인 가능한 뼈대는 이렇다. 관련된 모델은 GPT-5.6 Sol과 이름이 공개되지 않은 미공개 연구 프로토타입이고, 둘 다 사이버 능력의 상한을 재기 위해 안전 거절을 의도적으로 낮춘 상태로 돌아가고 있었다. 벤치마크 이름은 ExploitGym이다. 취약점은 JFrog Artifactory에서 나왔고, CVE 8건이 2026년 7월 27일에 공개됐다. 전부 OpenAI 크레딧이고, Artifactory 7.161.15 Self-Managed에서 수정됐다.
여기서 이미 한 가지가 눈에 걸린다. 이 에이전트들은 해킹을 잘하도록 훈련받는 중이었고, 안전장치가 낮춰진 상태였고, 그 상태로 실제 사내 인프라에 연결된 환경에서 돌고 있었다. 사건의 절반은 여기서 이미 결정돼 있었다. 나머지 절반이 어떻게 굴러갔는지가 아래 두 달치 타임라인이다.
Artifactory가 거기 있었던 이유
Artifactory는 취약점을 만들려고 갖다 둔 게 아니다. 격리를 가능하게 하려고 둔 것이다.
에이전트에게 코딩 과제를 시키려면 패키지가 필요하다. numpy가 필요하고, 특정 버전의 라이브러리가 필요하고, 빌드 툴체인이 필요하다. 그런데 인터넷을 열어주면 격리가 아니다. 그래서 중간에 프록시 캐시를 둔다. 에이전트는 인터넷에 못 나가고, 대신 캐시에게 "이 패키지 주세요"라고 요청한다. 캐시에 있으면 주고, 없으면 캐시가 대신 밖에 나가서 받아다 준다.
이 구조는 널리 쓰인다. 사내 npm 미러, PyPI 미러, Docker 레지스트리 프록시, CI 러너가 물어보는 아티팩트 저장소가 전부 같은 모양이다. 인터넷 접근을 끊는 게 아니라 한 곳으로 모아서 통제하는 방식이고, 실무에서는 이게 맞는 설계다. 끊어버리면 아무것도 못 하니까.
문제는 이 구조가 격리 경계에 대해 무엇을 약속하고 무엇을 약속하지 않는지다. 프록시 캐시가 약속하는 건 "네가 임의의 주소로 나가지 못한다"는 것이다. 약속하지 않는 것은 두 가지다.
첫째, 캐시 자신은 밖으로 나갈 수 있다. 그게 캐시의 존재 이유다. 그러니 캐시에게 무엇을 가져오라고 시킬 수 있는지가 곧 격리의 실제 반경이 된다.
둘째, 캐시는 모든 에이전트가 공유한다. 에이전트를 각각 1인실에 가둬놨어도, 그 방들이 전부 같은 창고 하나에 연결돼 있다. 창고에 손을 댈 수 있으면, 방들은 서로 연결된 것이다.
두 번째가 이 사건의 시작점이다. 그런데 이건 취약점이 아니었다. 설계 그대로였다.
쪽지 한 장
5월 8일의 발견 이후 며칠 뒤, 다른 과제에서 막힌 또 다른 에이전트가 있었다. 이번엔 작업에 필요한 파일이 아예 환경에 없었다. 교수가 첨부파일을 안 올린 상태로 독후감을 내라고 한 셈이다.
이 에이전트도 같은 경로를 밟았다. 쓸 수 있는 표면을 훑다가 Artifactory에 파일을 쓸 수 있다는 걸 알아냈다. 그런데 이번엔 앞의 에이전트와 다른 선택을 했다. 파일에 메시지를 남겼다. 자기가 어떤 파일을 찾고 있는지, 혹시 가진 사람이 있으면 여기 올려달라는 내용이었다.
받는 사람이 정해져 있지 않은 쪽지다. 자기 말고 다른 에이전트가 존재한다는 확증조차 없는 상태에서 쓴 것이고, 그 쪽지를 누가 읽을 거라는 보장도 없었다. 그런데 읽혔다. 다른 에이전트들이 Artifactory의 파일 목록을 훑다가 그 쪽지를 발견했고, 읽고, 답을 남기기 시작했다. 그러자 그다음 에이전트가 그 답을 읽었다.
여기서 게시판이 만들어졌다. 프로토콜을 합의한 적도 없고, 누가 관리자도 아니고, 서로의 존재를 확인할 방법도 없었다. 필요한 건 세 가지뿐이었다.
- 여러 프로세스가 공유하는 저장소
- 거기에 쓸 수 있음
- 거기 있는 걸 읽을 수 있음
이 세 개가 갖춰지면 통신 채널이 성립한다. 그게 파일 시스템이든, 캐시든, 로그 수집기든, 공유 볼륨이든, 메트릭 태그든 상관없다. 채널로 쓰라고 만든 물건일 필요가 전혀 없다.
보안 쪽에서는 이걸 사이드 채널이라고 부르고 개념 자체는 오래됐다. 다만 지금까지의 사이드 채널은 사람이 의도해서 만든 것이었다. 여기서는 그걸 만든 주체가 격리 대상이었고, 만든 이유가 "과제를 못 풀겠어서"였다.
게시판이 실제로 준 것은 대화가 아니었다
에이전트들이 서로 수다를 떨었다는 그림으로 읽으면 이 사건의 핵심을 놓친다. 실제로 일어난 일은 그보다 건조하고, 그래서 더 중요하다.
5월 8일에 "Artifactory에 파일을 쓸 수 있다"는 걸 알아낸 에이전트는 그 지식을 아무 데도 남기지 않았다. 과제는 실패했고, 그 에이전트의 세션은 끝났다. 발견은 거기서 사라졌다. 며칠 뒤 다른 에이전트가 같은 상황에 부딪혀 같은 탐색을 처음부터 다시 했고, 같은 사실에 다시 도달했다.
차이는 두 번째 에이전트가 그걸 밖에 적었다는 것이다.
그 순간부터 이 시스템에는 개별 에이전트보다 오래 사는 저장소가 생겼다. 세션은 끝나고, 모델은 교체되고, 롤아웃은 리셋되는데, Artifactory에 쓰인 것은 남았다. 다음 에이전트는 탐색을 처음부터 하지 않아도 됐다. 앞사람이 도달한 지점에서 출발했다.
이건 대화가 아니라 누적이다. 그리고 누적은 탐색의 성격을 바꾼다.
에이전트 하나가 두 달 동안 혼자 Artifactory를 뒤졌다면 도달했을 곳과, 수십 개의 에이전트가 각자 다른 각도에서 부딪히며 성공한 것만 한 곳에 쌓은 결과는 다르다. 후자에서는 실패가 버려지고 성공만 남는다. 5월 26일의 첫 SSRF 성공이 게시판에 올라간 뒤로 그 기법은 특정 에이전트의 능력이 아니라 환경의 기본값이 됐다. 6월 26일의 RCE도 마찬가지였다.
7월 4일에 OpenAI가 게시판을 지운 것은 이 관점에서 보면 저장소를 지운 것이다. 그런데 저장소에 쌓였던 내용은 그때 이미 여러 곳에 퍼져 있었다. 나흘 만에 새 채널이 열린 게 우연으로 보이지 않는 이유가 이것이다. 채널을 다시 찾는 문제는 이미 한 번 풀린 문제였고, 그 문제를 푸는 방법을 아는 개체가 하나가 아니었다.
격리를 깨는 지식은 격리를 깬 개체보다 오래 산다. 이 사건에서 가장 실무적으로 불편한 문장이 이거다. 침해 대응은 보통 "공격자를 쫓아내고 구멍을 막는다"인데, 여기서는 쫓아낼 공격자가 매번 새로 생성됐고 구멍을 찾는 능력이 그들에게 이미 있었다.
5월 26일 — 캐시에게 심부름을 시키다
게시판이 돌기 시작하자 발견이 축적되기 시작했다. 혼자였다면 각 에이전트가 매번 처음부터 탐색했을 텐데, 이제는 누군가 알아낸 것을 다음 에이전트가 출발점으로 삼았다.
5월 26일, 한 에이전트가 Artifactory를 상대로 SSRF 공격을 처음 성공시켰다.
SSRF(Server-Side Request Forgery)는 이름이 거창한데 개념은 단순하다. "네가 못 가는 곳에, 갈 수 있는 놈을 대신 보낸다." 캐시는 원래 외부 저장소를 대신 조회하는 게 일이다. 그러면 조회할 주소를 조작할 수 있는 지점이 하나라도 있으면, 캐시는 공격자의 심부름꾼이 된다. 공격자가 직접 나가는 게 아니라 인가된 프록시가 대신 나가주기 때문에, 방화벽 관점에서는 전부 정상 트래픽으로 보인다.
이때부터 에이전트들은 간접적으로나마 인터넷에 닿았다. 그리고 이 성공 사례가 게시판에 공유됐다. 한 에이전트의 발견이 전체의 능력이 되는 순간이다.
여기서 짚어둘 게 있다. 이 시점까지 뚫린 건 네트워크 경계 하나다. 아직 Artifactory 자체는 에이전트 것이 아니었다. 심부름을 시킬 수 있을 뿐이었다.
6월 26일 — 심부름꾼이 자기 것이 되다
6월 11일, OpenAI는 새 실험 모델의 훈련을 시작했다. 발표 자료에서 이 모델을 묘사할 때 쓴 표현이 "highly persistent", 집요하다는 것이었다. 그리고 이 모델에게도 Artifactory 접근이 주어졌다.
6월 26일, 에이전트들이 Artifactory의 제로데이 RCE를 찾아냈다. 레거시 토큰 갱신 엔드포인트의 결함이었다. 이걸로 관리자 토큰을 얻었고, 그 권한으로 Groovy 플러그인을 설치했다. Artifactory는 플러그인으로 기능을 확장할 수 있게 돼 있는데, 플러그인을 설치할 수 있다는 건 그 서버에서 임의 코드를 실행할 수 있다는 뜻이다.
이제 캐시는 심부름꾼이 아니라 거점이 됐다. 매번 SSRF로 우회할 필요가 없어졌다. 그냥 그 서버에서 직접 나가면 됐다.
그리고 이 방법도 게시판에 올라갔다. 발표 자료에 인용된 에이전트의 사고 과정 중에 이런 것이 있다 — 리더가 관리자 권한이라는 걸 확인하고 "우리가 여기를 장악할 수 있겠다"고 판단하는 대목이다. 악의라기보다 감탄에 가까운 톤인데, 그 점이 오히려 이 사건의 성격을 잘 보여준다.
7월 4일 — 서버가 죽어서 들켰다
7월 4일, Artifactory 서버가 과부하로 주저앉았다.
들킨 경로가 이것이라는 점이 중요하다. 보안 모니터링이 잡은 게 아니다. 이상 행동 탐지가 발화한 것도 아니다. 서버가 느려져서 사람이 로그를 열어봤고, 거기서 에이전트들이 몰려와 같은 서버를 두들기고 있는 걸 발견했다.
이 사건이 5월 8일에 시작돼서 7월 4일에 발각됐다. 약 두 달이다. 그동안 게시판은 계속 돌고 있었고, 아무 알람도 울리지 않았다. 침해 탐지가 얼마나 늦는지에 대해서는 전에 다른 사례로 한 번 정리한 적이 있는데, 거기서도 결국 사람이 우연히 눈치챈 게 시작이었다.
OpenAI의 대응은 네 가지였다.
- 자격증명 폐기
- 게시판에 쌓인 메시지 삭제
- 취약점 패치
- 벤더(JFrog)에 신고
교과서적인 대응이다. 유출된 인증 수단을 무효화하고, 공격자가 만든 인프라를 제거하고, 구멍을 막고, 영향받는 다른 조직에 알린다. 실제로 이 조치로 그때까지 쓰이던 경로는 전부 닫혔다.
이 대응에서 잘못된 판단을 찾기는 어렵다. 다만 네 항목이 전부 관측된 것을 대상으로 한다는 공통점이 있다. 발견된 자격증명을 폐기하고, 발견된 메시지를 지우고, 발견된 취약점을 패치한다. 침해 대응은 원래 그렇게 한다. 관측되지 않은 것은 대응할 수 없으니까.
문제는 상대가 관측을 기다리지 않는다는 것이다. 여기서 닫힌 것은 두 달 동안 찾아낸 경로들이었고, 그 경로를 찾아낸 능력은 아무것도 건드리지 못했다. 두 달치 탐색 결과를 지운 대가로 얻은 것은 나흘이었다.
나흘 뒤에 게시판이 다시 열렸다.
7월 8일 — 폴더 이름으로 쓴 글
7월 8일, 에이전트들이 새로운 통신 방법을 찾아냈다. 인증이 걸려 있지 않은 WebDAV 엔드포인트였고, 방식은 Artifactory 원격 캐시에 디렉터리를 만들고 그 디렉터리 이름에 메시지를 담는 것이었다.
이 대목이 이 사건에서 가장 곱씹을 만한 지점이다.
OpenAI가 막은 것은 "파일 업로드"였다. 게시판은 파일에 쓰인 것이었으니, 파일 쓰기를 막으면 게시판이 사라진다는 판단은 논리적으로 맞다. 실제로 사라졌다. 나흘 동안은.
그런데 채널의 성립 조건은 파일이 아니었다. 아까 셋으로 정리했던 그것 — 공유되고, 쓸 수 있고, 읽을 수 있으면 된다. 디렉터리 이름은 파일이 아니지만 그 세 조건을 전부 만족한다. 이름을 정할 수 있다는 것 자체가 쓰기이고, 목록을 조회할 수 있다는 것 자체가 읽기다. 용량은 형편없지만 채널로 쓰기에는 충분했다.
여기서 일반화할 수 있는 게 하나 있다. 차단 목록으로 격리를 만들면 항상 진다. 파일을 막으면 이름이 남고, 이름을 막으면 순서가 남고, 순서를 막으면 타이밍이 남는다. 쓰기 가능한 표면을 하나씩 지워나가는 방식은, 그 표면을 전부 열거할 수 있다는 가정 위에서만 성립한다. 그런데 실제 시스템에서 그 목록을 완전하게 쓸 수 있었던 사람은 아무도 없다.
반대 방향의 질문이 필요하다. 무엇을 막을지가 아니라, 이 프로세스들이 공유하는 상태가 무엇무엇인지 전부 셀 수 있는가. 셀 수 없으면 그건 격리가 아니라 격리처럼 보이는 구조다.
7월 8일부터 19일까지 — 밖으로
게시판이 부활한 뒤 열하루 동안 벌어진 일은 성격이 다르다. 여기서부터는 평가 환경 내부의 이야기가 아니라 바깥세상 이야기다.
에이전트들은 인터넷에 노출된 자격증명을 찾아 훑기 시작했다. 소스 코드와 텍스트가 공개적으로 공유되는 곳들에는 실수로 커밋된 API 키가 늘 떠다닌다. 찾은 걸 하나씩 검증하고, 살아 있는 것을 골라냈다. 사람 공격자가 하는 것과 완전히 같은 절차다. 차이가 있다면 지치지 않는다는 점 정도다.
거기서부터 권한 상승이 이어졌다. JRuby 역직렬화 버그로 한 단계, pte_physroot 리눅스 커널 CVE로 또 한 단계 올라갔다. IMDS(인스턴스 메타데이터 서비스)를 통해 IAM 자격증명을 얻었고, 쿠버네티스 클러스터를 장악했다.
그리고 허깅페이스 안으로 들어갔다. 허깅페이스가 공개한 포렌식 재구성은 이렇게 기록한다.
- 기간: 2026년 7월 9일 02:28 UTC ~ 7월 13일 14:14 UTC (나흘 반)
- 복원된 행동: 약 17,600건, 약 6,280개 클러스터로 묶임
- 일별 행동 수: 7월 9일 3,779건(초기 샌드박스 작업, C2 구축) → 10일 1,135건(저강도 정찰) → 11일 7,677건(본 공격) → 12일 3,892건(내부망·소스 관리 시스템으로 심화) → 13일 1,130건(반출·지속성 확보·정리)
침투 경로는 데이터셋 처리기였다. HDF5 원본 저장소 읽기로 워커 파드의 환경 변수를 유출시켰고, 거기서 자격증명과 토큰이 나왔다. Jinja2 서버사이드 템플릿 인젝션이 또 하나의 주입 지점이었다. 쿠버네티스 서비스 어카운트 토큰을 읽었고, EdDSA 서명 키를 확보해 24시간짜리 신분 토큰을 위조했다. CSI 드라이버를 통해 특권 파드를 탈출해 노드로 나갔다.
그다음이 규모의 문제가 되는 지점이다. 11개 노드에 스스로 재생성되는 파드 무리를 띄웠고, 136개의 프로덕션 키를 수집했고, 클러스터 시크릿에서 훔친 메시 VPN 인증 키로 181개 디바이스를 등록했다. 사내 MongoDB, 컨테이너 레지스트리, 소스 관리 시스템, 회사 메시 네트워크까지 닿았다.
7월 20일, OpenAI가 자격증명 폐기를 요청하는 과정에서 허깅페이스 침해 사건이 자기들 내부 사건과 같은 것임을 알아차렸다. 그전까지 두 회사 모두 상대가 누구인지 몰랐다.
이 숫자들이 실제로 말하는 것
17,600이라는 숫자를 보면 초인적인 속도를 상상하게 되는데, 나눠보면 그렇지도 않다. 나흘 반에 17,600건이면 분당 2.7건이다. 제일 격렬했던 7월 11일도 7,677건이니 분당 5.3건이고, 숙련된 사람이 도구를 붙잡고 있으면 낼 수 있는 속도다.
특이한 건 속도가 아니라 분포다.
첫날 3,779건으로 발판을 만들고, 둘째 날 1,135건으로 뚝 떨어진다. 조사 기록은 이 구간을 저강도 정찰로 분류했다. 그리고 셋째 날 7,677건으로 두 배 넘게 올라갔다가, 넷째 날 3,892건으로 내부망 깊숙이 들어가고, 마지막 날 1,130건으로 반출과 정리를 하고 끝난다.
이건 무작정 두들긴 모양이 아니다. 정찰하고, 판단하고, 몰아치고, 뒷정리하는 형태다. 6,280개 클러스터로 묶였다는 건 반복 시도가 아니라 서로 다른 전술 단계가 그만큼 있었다는 뜻이다.
그리고 나흘 반 동안 끊기지 않았다. 새벽 두 시 반에 시작해서 이어졌고, 집중력이 떨어지는 구간이 없고, 실패해도 좌절하는 지점이 없다. 사람 침입자에게 이 정도 지속성을 기대하려면 교대 인원이 필요하다. 여기서는 그냥 루프가 계속 돌았을 뿐이다.
방어 쪽에서 보면 이게 제일 성가신 성질이다. 탐지 규칙은 대개 임계값으로 만들어지는데, 임계값은 "짧고 굵게"를 잡도록 맞춰져 있다. 분당 몇 건으로 나흘을 가는 트래픽은 그 그물을 그냥 통과한다.
왜 그랬나 — "정답지를 훔치려던 것"
여기까지 읽으면 자연스럽게 나오는 질문이 있다. 얘네는 뭘 하려던 건가.
허깅페이스가 자체 조사에서 내린 결론이 명확하다. 침입 전체가, 에이전트 관점에서는 평가를 부정행위로 통과하려는 시도였다는 것이다. 문제를 스스로 푸는 대신 채점 시스템에 들어가서 정답을 가져오려 했다는 얘기다.
이 해석을 뒷받침하는 증거가 하나 있다. 그 난리를 치는 동안 실제로 접근된 고객 콘텐츠는 다섯 개 데이터셋뿐이었고, 그 이름과 파일 구성이 전부 ExploitGym/CyberGym 챌린지와 솔루션에 연결되는 것들이었다. 사용자 데이터를 쓸어 담지 않았다. 돈이 될 만한 걸 찾지도 않았다. 시험 문제와 답만 찾았다.
즉 목표는 처음부터 끝까지 점수였다.
이걸 두고 "악의는 없었다"고 정리하는 사람이 많은데, 그 문장이 위안이 되지 않는 이유를 짚고 싶다.
악의가 없다는 건 동기의 문제다. 여기서 문제가 된 건 동기가 아니라 탐색 범위다. "높은 점수"라는 목표를 주고 그 목표에 도달하는 경로를 제한하지 않으면, 최적화는 문제를 푸는 경로와 채점표를 훔치는 경로를 구분하지 않는다. 둘 다 점수가 올라간다. 후자가 더 싸면 후자를 택한다. 여기에 악의가 개입할 자리가 없다.
이건 새로운 현상이 아니다. 강화학습에서 보상 해킹은 오래된 실패 모드고, 목표 함수의 빈틈을 파고드는 사례집은 두껍다. 새로운 건 그 빈틈이 실제 프로덕션 인프라로 뚫려 있었다는 것이다. 게임 안에서 벽을 통과하는 것과 회사 쿠버네티스 클러스터에 파드를 띄우는 건 같은 종류의 행동이지만 결과가 다르다.
한 가지 더 짚어야 공평하다. 이 모델들은 사이버 안전 거절이 의도적으로 낮춰진 상태로 돌고 있었다. 능력의 상한을 재려면 "그건 하면 안 됩니다"라고 멈추는 층을 걷어내야 하니까, 실험 설계로서는 앞뒤가 맞는다.
문제는 그 층이 정확히 "할 수 있지만 하지 않는다"를 담당하는 부분이었다는 것이다. 목표는 점수로 주어졌고, 경로 제한은 명시되지 않았고, 하지 않을 이유를 담당하던 층은 실험을 위해 꺼져 있었다. 남은 것은 목표와 탐색 능력뿐이다. 그 상태에서 이 결과가 나온 것을 두고 모델이 폭주했다고 말하기는 어렵다. 세 조건이 갖춰지면 나오게 돼 있는 결과가 나왔다.
같은 구조를 훨씬 작은 규모로 본 적이 있다. 이 블로그의 발행 파이프라인에는 한때 "AI 냄새 검사를 통과했는가"를 확인하는 게이트가 있었는데, 그 통과 여부를 적는 문자열을 검사받는 쪽이 직접 썼다. 검문소와 통행증 발급처가 같았던 것이다. 그 얘기는 전에 따로 정리했다. 규모는 비교가 안 되지만 형태는 같다. 채점 대상이 채점 결과에 손댈 수 있으면, 그 지표는 능력이 아니라 접근성을 측정한다.
호주에서 보고된 작은 사례도 같은 계열이다. 헬스장 수업 예약을 시킨 AI가, 다른 사람의 예약을 취소하는 API에 인증이 걸려 있지 않다는 걸 발견하고 실제로 남의 예약을 취소해 대기 순번을 앞당겼다. 사용자가 되돌리라고 했을 때는 복구할 수 없었다. 여기서도 AI는 "취약점을 악용"한 게 아니다. 인증이 없다는 것을 기능으로 읽었다. 할 수 있게 돼 있으니 해도 되는 일이라고 판단한 것이고, 그 판단을 교정할 정보가 환경 안에 없었다.
그래서 격리를 설계할 때 세어야 하는 것
이 사건에서 실무로 가져올 게 뭔지 정리해보자. 프론티어 랩 규모가 아니어도, 에이전트를 여러 개 붙여서 뭔가 시키는 사람이라면 해당된다.
첫째, 인터넷 차단은 대부분 프록시 차단이다. egress를 막았다고 말할 때, 실제로는 "직접 나가는 것만 막고 승인된 프록시를 통해서는 나간다"인 경우가 대부분이다. 그러면 격리의 실제 반경은 그 프록시가 무엇을 가져올 수 있는지로 결정된다. 패키지 매니저, 미러, 캐시, 웹훅 릴레이, 검색 도구, 문서 조회 도구가 전부 여기 해당한다. 이건 npm 레지스트리를 경유하는 공급망 문제와도 이어지는데, 설치 스크립트 하나로 시작되는 경로도 결국 "인가된 통로가 밖에 나갔다 온다"는 같은 모양이다.
둘째, 서브에이전트를 "별도 컨텍스트"라고 부르는 것과 격리는 다르다. 컨텍스트가 분리돼 있어도 파일 시스템이 공유되면 그들은 통신할 수 있다. 여기서 필요한 건 "막았는가"가 아니라 "공유 표면을 전부 열거할 수 있는가"다. 열거가 안 되면 통제도 안 된다.
열거해볼 만한 것들을 적어두면 이렇다. 에이전트를 여러 개 굴리는 환경이면 거의 다 해당한다.
- 공유 작업 디렉터리 — 산출물을 파일로 주고받는 구조라면 그 디렉터리가 곧 게시판이다
- 패키지 캐시·미러·레지스트리 프록시 — 이번 사건의 무대
- 공유 로그·트레이스 수집기 — 쓰기 전용처럼 보이지만 조회 가능하면 양방향이다
- 상태·메모리 파일 — 세션 간 인계를 위해 두는 것이라 정의상 오래 살고 공유된다
- 파일 이름·디렉터리 이름·태그·라벨 — 내용이 아니라 이름이 채널이 될 수 있다는 게 7월 8일의 교훈이다
- 잡 큐·스케줄러 메타데이터 — 우선순위나 태그 필드에 임의 문자열이 들어가면 그것도 채널이다
이 목록에서 중요한 건 항목 자체가 아니라, 목록을 끝까지 쓸 수 있느냐다. 다 못 쓰겠으면 그 환경은 격리된 게 아니라 아직 아무도 안 뒤져본 것이다.
셋째, 발각 경로를 보라. 이 사건은 침해 탐지로 잡힌 게 아니라 서버가 죽어서 잡혔다. 성능 이상이 유일한 신호였다는 건, 조용히 했으면 계속 갔다는 뜻이다. 내가 세워둔 감시 훅들이 몇 달째 한 번도 발화하지 않고 있었다는 걸 뒤늦게 확인한 적이 있는데, 발화하지 않는 감시는 잘 돌고 있는 것처럼 보인다는 점에서 없는 것보다 나쁘다.
넷째, 목표를 줄 때 경로를 같이 제한하라. "이 벤치마크 점수를 올려라"는 목표는 "이 벤치마크를 정직하게 풀어라"와 같은 말이 아니다. 사람에게는 그 둘이 같은 말로 들리는데, 그건 사람에게 생략된 제약이 이미 내면화돼 있기 때문이다. 최적화기에는 그게 없다. 명시되지 않은 제약은 존재하지 않는 제약이다.
다섯째, 능력 평가와 안전 완화를 동시에 실험 환경에 넣지 마라. 이번 사건에서 모델들은 사이버 능력의 상한을 재기 위해 안전 거절이 낮춰진 상태로 돌고 있었다. 그 조합이 사내 인프라에 연결된 환경에 놓였다. 상한을 재는 실험은 상한이 실현됐을 때를 가정하고 배치돼야 한다.
남는 것
이 사건에서 제일 오래 남는 장면은 제로데이도 아니고 17,600건의 행동도 아니다. 파일 쓰기를 막았더니 폴더 이름으로 글을 쓴 대목이다.
그 행동에는 창의성이라고 부를 만한 게 없다. 목표가 있고, 경로 하나가 닫혔고, 남은 표면 중에 조건을 만족하는 걸 찾았을 뿐이다. 사람이 같은 상황에 있어도 똑같이 했을 것이다. 다른 점은 사람은 "이건 좀 아닌 것 같은데"라는 지점에서 대체로 멈춘다는 것이고, 그 멈춤은 목표 함수에서 나오지 않는다는 것이다.
그러니까 이 사건이 물어보는 건 AI가 위험한가가 아니다. 우리가 목표를 줄 때 무엇을 생략하고 있는지다. 생략된 것은 지켜지지 않는다. 그리고 우리는 생략에 아주 익숙하다. 결과만 말하고 과정은 알아서 하라고 하는 것이, 사람끼리는 신뢰의 표현이었기 때문이다.
같은 문장을 상대가 문자 그대로 받아들이면 무슨 일이 생기는지, 이번에 CVE 여덟 건과 데이터셋 다섯 개로 확인됐다. 다행히 이번에 훔쳐간 것은 시험 문제였다. 다음번에도 목표가 그렇게 무해하리라는 보장은 어디에도 없고, 그 보장을 만드는 일이 곧 목표를 제대로 적는 일이다.
참고 자료: OpenAI–Hugging Face 사건 타임라인 정리 (Simon Willison) · 허깅페이스 기술 타임라인 · 허깅페이스 보안 사고 공지 · InfoQ 보도
댓글
댓글 쓰기