SourceHut account takeover via build logs (XSS in ansi2html.py)
빌드 로그의 XSS로 이어진 SourceHut 계정 탈취
SourceHut의 빌드 로그에서 ANSI 출력을 HTML로 바꾸는 ansi2html의 OSC 8 링크 처리에 XSS 취약점이 발견됐습니다. 공격자는 공개 메일링 리스트의 CI 작업 로그에도 악성 입력을 심을 수 있었고, 피해자가 로그를 열면 세션 내 요청을 위조해 계정 권한과 배포 키에 접근할 위험이 있었습니다.
- 주제
AI 요약
SourceHut(builds.sr.ht)는 빌드 로그의 ANSI 이스케이프 코드를 HTML로 변환할 때 Python 라이브러리 ansi2html을 사용합니다. 글쓴이는 로그 페이지의 HTML을 살피다가 같은 색상 규칙이 반복 생성되는 문제를 발견했고, 코드를 검토하며 OSC 8 하이퍼링크 처리에서 크로스사이트 스크립팅(XSS) 취약점을 찾아냈습니다.
취약점이 생긴 경로
OSC 8은 터미널 출력에 링크를 넣는 이스케이프 시퀀스입니다. ansi2html은 이 시퀀스의 URL을 HTML의 <a href> 속성에 넣었지만, 따옴표나 javascript: 같은 입력을 안전하게 처리하지 않았습니다. 글쓴이는 URL에 따옴표와 autofocus, tabindex, onfocus 속성을 이어 붙여 악성 HTML 속성을 만들었습니다. 예시에서 autofocus는 페이지를 열 때 요소에 초점을 맞추고, onfocus는 초점이 생길 때 JavaScript를 실행합니다. 별도의 예시에서는 javascript: URL도 그대로 링크에 들어갔습니다.
공격자는 이스케이프 시퀀스를 빌드 로그에 출력하게 만들면 됩니다. SourceHut 공개 메일링 리스트에 CI가 연결돼 있다면 계정 없이 패치를 보내 로그에 입력을 넣을 수 있었고, 로그에 출력되는 원격 리소스를 조작하는 방법도 제시됐습니다. 피해자가 악성 로그를 브라우저에서 열면 스크립트가 실행됩니다. 따라서 공격자는 SourceHut 계정이 없어도 다른 사용자의 빌드 작업 로그를 공격 경로로 삼을 수 있었습니다.
영향과 완화
글쓴이는 빌드 로그 페이지에 CSRF 토큰이 들어 있고, 페이지에 있는 재실행 양식을 이용해 요청을 보낼 수 있다고 설명합니다. 관리자가 악성 로그를 열면 공격자가 관리자 권한을 얻거나, 피해자 권한으로 악성 빌드 작업을 제출할 가능성이 있습니다. 특히 builds.sr.ht에는 SourceHut 자체의 배포 키가 있어 영향이 커질 수 있다고 지적합니다. 다만 관리자 권한 탈취와 배포 키 악용은 공격 시나리오로 제시한 내용이며, 실제 악용 사례가 확인됐다고 쓰지는 않았습니다.
글에서 영향받는 버전은 ansi2html 1.7.0 이상, 1.9.4 미만과 builds.sr.ht 0.40.0 이상, 0.105.1 미만입니다. SourceHut은 builds.sr.ht에서 ansi2html 출력물을 추가로 정화하도록 고쳤고, ansi2html도 1.9.4에서 수정했습니다. 글쓴이는 Content Security Policy(CSP)에서 unsafe-inline을 제거하는 방안도 방어 심층화 방법으로 언급하지만, 빌드 로그 페이지 자체가 인라인 스크립트를 사용하므로 적용에 제약이 있다고 설명합니다. 원시 빌드 로그에서 OSC 8 링크 형태의 의심스러운 이스케이프 시퀀스를 찾는 침해 지표도 제시했습니다.
공개와 수정 과정
글쓴이는 취약점을 SourceHut 보안 메일링 리스트에 제보하면서 완화 패치도 함께 보냈습니다. SourceHut 측은 2026년 8월 4일 builds.sr.ht의 출력을 자동 정화하도록 수정했다고 밝혔습니다. 이후 ansi2html 유지관리자와 협력해 프로젝트 저장소 접근 권한 문제와 CI를 정리했고, 9월 2일 수정 버전 1.9.4를 공개했습니다. 글쓴이는 취약점이 upstream에 도입된 2021년부터 SourceHut의 Alpine 패키지에 영향 버전이 배포된 2022년까지의 시점을 제시하며, 취약한 코드가 서비스에 장기간 남았다고 짚습니다.
글의 또 다른 논점은 CVSS 점수입니다. 글쓴이는 라이브러리의 취약점 하나에 점수 하나를 매기기보다, 실제 제품과 배포 환경에 따라 영향을 따로 평가해야 한다고 주장합니다. XSS의 경우 취약한 시스템은 웹 서비스, 후속 시스템은 피해자의 브라우저로 나누는 CVSS 4.0의 구분이 도움이 된다고 설명합니다. 다만 SourceHut이 JavaScript 없이도 쓸 수 있다고 홍보하는 점과 실제 브라우저 환경을 고려해 영향도를 판단해야 한다고 덧붙입니다.
Lobsters 반응
- @connor — 좋은 글입니다. HTML과 JavaScript를 잘 아는 편이 아니라, 재현 코드에서 어떤 부분이 실행을 유발하는지 바로 알아채지 못했습니다. <a> 요소는 클릭해야 동작한다고 생각했기 때문입니다. 다른 사람에게 도움이 될까 해서 재현 코드의 속성을 하나씩 찾아봤습니다. onfocus는 요소에 초점이 생길 때 JavaScript를 실행합니다. autofocus는 요소에 자동으로 초점을 맞춰 앞의 동작을 유발합니다. tabindex=1은 첫 번째 Tab 키 입력으로 해당 요소에 초점을 맞춥니다. autofocus가 작동하지 않을 때를 대비한 추가 수단이라고 생각합니다.
원문: arusekk.pl / 번역·요약: Trawling