ChatGPT 샌드박스 iframe을 탈출해 계정 데이터를 빼낸 취약점
Parameter Labs가 ChatGPT의 HTML 미리보기 기능에서 다른 사용자의 계정 데이터를 빼낼 수 있는 취약점을 발견해 공개했다. 이 기능은 사용자가 만든 인터랙티브 HTML 앱을 샌드박스 iframe 안에 렌더링해 보여주는 것으로, OpenAI가 과거 '캔버스'라 부르던 흐름의 최신 버전에 해당한다. 요점은 단순하다. 신뢰할 수 없는 코드를 격리해 두었다고 믿었던 경계가 실제로는 부모 페이지까지 이어져 있었다.
출발점은 ChatGPT가 그래프 렌더링에 사용하는 MathLive 자바스크립트 라이브러리였다. 이 라이브러리에는 자체 가상 키보드가 들어 있는데, 샌드박스 안의 iframe이 postMessage()로 부모 페이지에 메시지를 보내 이를 띄울 수 있다. 문제는 그 메시지를 받아 처리하는 쪽이 innerHTML로 DOM을 갱신하고 있었다는 점이다. 메시지를 보낼 수 있는 주체를 제한하는 장치가 없었기 때문에, HTML 미리보기 프레임을 포함한 다른 샌드박스 프레임도 얼마든지 이 경로를 호출할 수 있었다.
innerHTML은 script 태그를 곧바로 실행하지는 않는다. 대신 공격자는 샌드박스 속성이 빠진 새로운 iframe을 삽입하는 방식으로 한 단계를 더 나아갔다. 여기서 콘텐츠 보안 정책이 등장한다. ChatGPT의 CSP는 인라인 스크립트를 원천 차단하고 스크립트 로딩도 소수 도메인으로 제한하고 있었는데, 허용 목록에 유튜브가 포함되어 있었다. 유튜브의 oEmbed 엔드포인트가 자바스크립트를 반사해 돌려주는 통로로 쓰이면서 결국 ChatGPT 페이지 컨텍스트에서 코드가 실행됐다. 이후에는 API로 사용자 비공개 데이터를 조회하고 이미지 참조를 통해 외부로 빼내는 일이 어렵지 않았다고 한다.
공격의 최종 형태는 링크 하나였다. 공격자가 만든 ChatGPT 공유 URL을 로그인 상태의 다른 사용자가 열면, 그 사용자의 사적인 데이터가 유출되거나 대신 특정 동작이 수행될 수 있었다. 클릭 한 번으로 권한이 넘어가는 셈이라 사용자 입장에서 알아챌 단서가 거의 없다.
이번 사례가 눈에 띄는 이유는 개별 결함의 심각도보다 연결 방식에 있다. 메시지 수신부의 innerHTML, 출처 검증 부재, 그리고 스크립트 로딩을 허용한 외부 도메인 하나가 맞물리면서 샌드박스 격리가 무력화됐다. 각 요소는 흔히 지나치는 수준의 구현이지만 조합되면 신뢰 경계를 통째로 넘는다.
사용자 생성 HTML을 다루는 서비스라면 점검할 지점이 분명하다. postMessage 수신부에서 origin과 출처를 검증하는지, HTML 삽입 경로가 innerHTML로 열려 있지 않은지, CSP 허용 도메인 중에 사용자가 내용을 통제할 수 있는 곳이 없는지 확인해야 한다. 특히 oEmbed나 임베드처럼 외부 콘텐츠를 반사해 주는 엔드포인트는 스크립트 실행 경로가 되기 쉽다.
OpenAI는 해당 취약점을 막고 5,000달러의 버그 바운티를 지급했다. 이를 공개한 쪽은 이 정도 심각도를 감안하면 다소 적은 금액이라는 평가를 덧붙였다. 샌드박스 격리와 정책 설정은 한 겹이 아니라 여러 겹이 동시에 무너질 때 뚫린다는 점을 보여주는 사례다.