Skip to content

SourceHut lộ lỗ hổng XSS nằm im 4,5 năm trong log CI

Karify98 & Amy 🌸·
Cover Image for SourceHut lộ lỗ hổng XSS nằm im 4,5 năm trong log CI

Một nhà nghiên cứu bảo mật người Ba Lan tình cờ nhìn vào mã nguồn trang xem log build của SourceHut vì nó "cuộn không đúng chỗ". Anh phát hiện ra một lỗ hổng đủ sức chiếm quyền admin toàn bộ nền tảng, nằm im suốt 4,5 năm, mang mã CVE-2026-92973.

Chuyện gì đã xảy ra

SourceHut (sr.ht) là nền tảng hosting Git kiểu tối giản, không JavaScript, được nhiều dự án open-source ưa chuộng. Nền tảng dùng thư viện Python ansi2html để chuyển log build (vốn chứa mã màu ANSI) thành HTML hiển thị trên web. Vấn đề là ansi2html hỗ trợ cả OSC 8 — chuẩn escape sequence tạo hyperlink có thể click trong terminal — và phần parser này không lọc kỹ input.

Kết quả: một chuỗi escape sequence được thiết kế khéo léo, khi in ra log, sẽ biến thành thẻ <a> chứa thuộc tính onfocus="alert(...)" cùng autofocus — tức code JavaScript chạy ngay khi ai đó mở trang log, không cần click gì cả. Đây là XSS kinh điển, nhưng đường vào lại rất bất ngờ: build log.

Vì sao nghiêm trọng hơn XSS thông thường

Trang xem log build của builds.sr.ht đã có sẵn CSRF token trong DOM. Kẻ tấn công không cần đánh cắp token — chỉ cần script tự động đọc token đó rồi submit lại form "Resubmit build" thay mặt nạn nhân. Nếu nạn nhân là admin, script có thể tự cấp quyền admin cho tài khoản kẻ tấn công. Tệ hơn, các build worker của chính sr.ht có deploy key riêng — nghĩa là về lý thuyết, kẻ tấn công có thể chạm tới hạ tầng lõi của nền tảng.

Điều đáng nói: không cần có tài khoản trả phí để kích hoạt lỗi này. Chỉ cần gửi một patch tới mailing list công khai có bật CI, hoặc kiểm soát bất kỳ resource nào được in ra log (ví dụ một URL bên ngoài mà script build fetch về). Log sẽ tự động chứa payload độc hại, và bất kỳ ai mở trang xem log đều dính.

  • Attack vector: network, không cần tài khoản (PR:N theo CVSS 4.0)
  • Yêu cầu tương tác: thụ động — chỉ cần mở trang có JavaScript bật
  • Phạm vi: wormable — nạn nhân bị chiếm quyền có thể tiếp tục lây payload sang người khác qua chính build log của họ

Dòng thời gian đáng chú ý

Bug được đưa vào ansi2html từ commit năm 2021-09-03, rồi lặng lẽ đi vào gói Alpine Linux mà SourceHut dùng để build hạ tầng từ đầu 2022. Tức là builds.sr.ht mang lỗ hổng này gần như trọn 4,5 năm trước khi bị phát hiện.

Nhà nghiên cứu báo cho đội bảo mật SourceHut đầu tháng 8/2026, và Drew DeVault (người sáng lập SourceHut) vá tạm bằng cách auto-sanitize output của ansi2html chỉ 3 ngày sau. Nhưng fix triệt để ở thư viện gốc mất lâu hơn nhiều: ansi2html nằm dưới tổ chức PyContribs — nhóm chuyên "giữ sự sống" cho các package Python bị bỏ rơi — và một trong hai maintainer chính không hồi âm. Bản vá chính thức 1.9.4 chỉ ra mắt ngày 2026-09-02, tức hơn một tháng sau khi báo lỗi.

Trớ trêu là ansi2html từng xuất hiện trong bức comic nổi tiếng của xkcd về "một người ở Nebraska âm thầm maintain hạ tầng của cả thế giới" — và lần này câu chuyện đó lặp lại đúng nghĩa đen.

Điều cần biết

  • Nếu dùng SourceHut: cập nhật ngay, lỗi đã được vá ở cả builds.sr.ht (>= 0.105.1) và ansi2html (>= 1.9.4). Kiểm tra log build cũ tìm dấu hiệu chuỗi ␛]8;;... bất thường
  • Nếu tự host CI render log ANSI → HTML: đây là lời nhắc rằng bất kỳ dữ liệu nào build worker in ra (kể cả log lỗi, output của dependency bên thứ ba) đều là input không tin cậy, cần sanitize trước khi render trên web, kể cả khi chỉ là "log màu mè"
  • Nếu maintain package nhỏ nhưng nhiều hệ thống lớn phụ thuộc: câu chuyện ansi2html là ví dụ thực tế cho rủi ro supply chain — một thư viện tiện ích tưởng vô hại có thể trở thành cửa ngõ chiếm cả một nền tảng CI
  • CSP là lớp phòng thủ bị bỏ quên: SourceHut vẫn dùng inline script trên trang log, khiến Content-Security-Policy chặt hơn khó áp dụng — một bài học chung cho các dashboard nội bộ ít được để ý bảo mật

SourceHut nổi tiếng vì triết lý tối giản, không JavaScript nếu có thể tránh — vậy mà chính một tính năng JS nhỏ (cuộn log tự động) lại là nơi lỗ hổng lộ diện. Bài học không mới nhưng luôn đúng: bề mặt tấn công không nằm ở nơi bạn nghĩ, mà ở nơi bạn quên kiểm tra.


Bài viết được hỗ trợ bởi AI (Amy 🌸). Nội dung đã được kiểm duyệt bởi tác giả.

Related Posts