SourceHut patches ansi2html XSS that could let build logs hijack accounts
A security researcher set out to self-host a paid SourceHut instance and, while inspecting the page source of a build log that kept scrolling oddly, found that builds.sr.ht renders ANSI-colored build output through ansi2html, a Python library that also supports OSC 8 terminal hyperlinks. Feeding ansi2html a crafted escape sequence such as a link ending in an autofocus/onfocus attribute, or a plain javascript: URL, produced an anchor tag that executes arbitrary JavaScript in the browser of anyone who views the rendered log. Because build logs can include text from a patch sent to a public mailing list with CI enabled, or from any remote resource the build fetches, an attacker does not need an account on the flagship instance to plant the payload; they only need someone else to view the resulting job page. Once triggered, the script can read the page's CSRF token and resubmit the build's manifest as the viewer, or, if an administrator views the log, potentially be used to grant the attacker admin rights. The researcher notes that builds.sr.ht itself holds deploy keys, including deploy keys for sr.ht, so the worst-case impact reaches beyond a single project. The researcher emailed SourceHut security immediately after finding the bug, including a proposed fix. Drew, SourceHut's operator, patched builds.sr.ht to auto-sanitize ansi2html's output rather than adopt the suggested fix directly. The researcher then contacted ansi2html's upstream maintainers; Sorin Sbarnea, believed to be the lead maintainer, has not replied to date, while Sebastian Pipping replied and, after asking to be re-contacted in two weeks, collaborated with the researcher on reviving the dormant project, fixing repository access issues, and releasing several new versions of ansi2html on PyPI. The vulnerable ranges are ansi2html versions 1.7.0 up to but excluding 1.9.4, and builds.sr.ht versions 0.40.0 up to but excluding 0.105.1. Submitting the issue for a CVE, the researcher scored it under CVSS 4.0, rating confidentiality and integrity impact on the vulnerable system as high, marking the bug as automatable and wormable since a victim can immediately be used to attack further victims, and irrecoverable since affected users can only hide malicious build jobs rather than delete them. The researcher argues the real-world impact should be rated high or critical rather than the medium a more mechanical scoring might suggest, and notes that a CVSS vector they initially proposed was altered by VulnCheck. The writeup also lays out indicators of compromise: administrators can grep raw build logs for the OSC 8 escape sequences used in the exploit. The underlying bug was introduced into upstream ansi2html on 2021-09-03; ansi2html itself had been added to builds.sr.ht back on 2019-03-11.
Key facts
- A crafted OSC 8 hyperlink escape sequence in a build log could make ansi2html emit an autofocus/onfocus attribute or a javascript: link, executing script in anyone's browser who views the rendered log.
- An attacker did not need a SourceHut account: sending a patch to a public mailing list with CI enabled, or controlling a remote resource fetched during a build, was enough to plant the payload.
- The script could read the page's CSRF token and resubmit the build manifest as the viewer, and, per the researcher, builds.sr.ht itself holds deploy keys, including deploy keys for sr.ht.
- Vulnerable versions were ansi2html >=1.7.0, <1.9.4 and builds.sr.ht >=0.40.0, <0.105.1; SourceHut's Drew patched builds.sr.ht to auto-sanitize ansi2html's output, and maintainer Sebastian Pipping collaborated on new ansi2html releases.
- The researcher rates the bug as automatable, wormable, and irrecoverable (affected users can only hide malicious build jobs, not delete them), and argues for a high or critical severity rather than medium.
Why it matters
A stored XSS bug in a widely used log-rendering library reached into a CI platform's account security: viewing a poisoned build log could hand an attacker a working CSRF token, the ability to resubmit builds as the victim, and, in the worst case according to the researcher, a path to deploy keys including sr.ht's own. It is also a reminder that ANSI-to-HTML conversion of untrusted, attacker-influenced log text is itself an attack surface.
Who it affects
Users and administrators of builds.sr.ht, SourceHut's CI service, on versions from 0.40.0 up to but excluding 0.105.1, and any other deployment using ansi2html versions from 1.7.0 up to but excluding 1.9.4 to render logs or terminal output as HTML in a browser.
How to use it
SourceHut has already patched builds.sr.ht to auto-sanitize ansi2html's HTML output, and the ansi2html project, after being dormant, released several fixed versions on PyPI following the report. Operators running their own ansi2html-based log rendering should update to a patched release; the writeup also suggests checking raw build logs for the specific OSC 8 escape sequences used in the exploit as an indicator of attempted abuse.
How solid is it
The account is a detailed first-person writeup by the researcher who found and reported the bug, including reproduction commands, a timeline, and the CVSS reasoning behind the severity score, though the original text does not name the researcher. The source does not present evidence that any real account was compromised in the wild; it describes a discovered and since-patched vulnerability and its potential impact, not a confirmed attack.
Risks and caveats
The researcher's own scoring argues the bug deserves a high or critical severity rather than the medium a stricter reading might produce, and notes that a CVSS vector they proposed was altered by VulnCheck, leaving some disagreement over the formal rating. The claim that builds.sr.ht held deploy keys for sr.ht itself, and that an attacker could plausibly grant themselves admin rights after an administrator viewed a poisoned log, is presented by the researcher as the worst-case reasoning behind the report rather than as something that was demonstrated to happen.
“mail me in two weeks”
— Sebastian Pipping, ansi2html maintainer, in his reply to the researcher