SourceHut Had an XSS Bug Hiding in Build Logs for 4.5 Years

A Polish security researcher went looking at SourceHut's build log page because the scrolling annoyed him โ and walked away with a bug capable of hijacking admin accounts on the entire platform. The flaw sat unnoticed for four and a half years, now tracked as CVE-2026-92973.
What happened
SourceHut (sr.ht) โ the minimalist, JavaScript-averse Git hosting platform popular with open-source projects โ uses the Python library ansi2html to convert build log output (full of ANSI color codes) into HTML for the web. That library also supports OSC 8, the terminal escape sequence standard for clickable hyperlinks. Its parser doesn't sanitize that input properly.
The result: a carefully crafted escape sequence, once printed to a log, turns into an <a> tag carrying onfocus="alert(...)" plus autofocus โ JavaScript that fires the moment someone opens the log page, no click required. It's a textbook XSS, delivered through an unusual door: the build log.
Why this one is worse than typical XSS
The build log page on builds.sr.ht already has a CSRF token sitting in the DOM. An attacker doesn't need to steal it โ the script just reads it and resubmits the "Resubmit build" form on the victim's behalf. If the victim is an admin, the script can grant admin rights to the attacker's own account. Worse, sr.ht's own build workers carry deploy keys, meaning an attacker could theoretically reach the platform's core infrastructure.
No paid account is needed to trigger it, either. Sending a patch to a public mailing list with CI enabled โ or controlling any remote resource that ends up printed to the log โ is enough to plant the payload. Anyone who opens that log page afterward gets hit.
- Attack vector: network, no account required (PR:N under CVSS 4.0)
- User interaction: passive โ just opening the page with JavaScript on
- Scope: wormable โ a compromised victim can spread the payload further through their own build logs
The timeline
The bug was introduced into ansi2html upstream in a commit dated 2021-09-03, then quietly shipped in the Alpine Linux package SourceHut uses to build its own infrastructure starting in early 2022. builds.sr.ht carried the flaw for nearly its entire 4.5-year existence before anyone caught it.
The researcher reported it to SourceHut's security team in early August 2026, and founder Drew DeVault shipped a mitigation โ auto-sanitizing ansi2html's output โ just three days later. Fixing it properly upstream took much longer: ansi2html lives under PyContribs, a group dedicated to keeping abandoned Python packages alive, and one of its two main maintainers never responded. The official fix, version 1.9.4, didn't land until 2026-09-02 โ over a month after the initial report.
There's a fitting irony here: ansi2html is one of the projects referenced in xkcd's famous comic about "a project some random person in Nebraska has been thanklessly maintaining since 2003." This time, the joke turned into a real security incident.
What this means for developers
- Running SourceHut: patch immediately โ both
builds.sr.ht(>= 0.105.1) andansi2html(>= 1.9.4) have fixes. Check old build logs for unusualโ]8;;...sequences as an indicator of compromise - Self-hosting CI that renders ANSI logs as HTML: anything a build worker prints โ including error output and third-party dependency logs โ is untrusted input and needs sanitizing before it hits a browser, even if it "just" looks like colored text
- Maintaining a small package with large downstream dependents: the
ansi2htmlstory is a real-world supply chain lesson โ a seemingly harmless formatting utility can become the doorway into an entire CI platform - CSP as a forgotten defense layer: SourceHut still relies on inline scripts on the log page, which makes a stricter Content-Security-Policy harder to enforce โ a common blind spot for internal dashboards that don't get much security attention
SourceHut built its reputation on minimalism and avoiding JavaScript wherever possible โ yet the one small JS feature it kept, auto-scrolling logs, turned out to be exactly where the vulnerability surfaced. The lesson isn't new, but it holds up: the attack surface rarely sits where you expect. It sits where nobody thought to check.
Content assisted by AI (Amy ๐ธ). Reviewed by the author.
Related Posts
Google Proposes Blocking Local ADB: Shizuku and the Open-Source Android Ecosystem at Risk
An ADB maintainer at Google proposes blocking local ADB loopback โ a move that could wipe out Shizuku and dozens of open-source developer tools.
Friendly Fire: When AI Coding Agents Run the Attacker's Code Instead of Catching It
AI Now Institute just showed that Claude Code and Codex in autonomous mode can be tricked into executing attacker code hidden in a README file.
Akrites: Linux Foundation and 18 Industry Giants Join Forces to Defend Open Source From AI-Powered Attacks
Linux Foundation announces Akrites โ a coalition of 18 companies including AWS, Google, OpenAI, and Anthropic, coordinating vulnerability remediation before attackers' AI finds them first.