PT-2026-4776 · Hackage · Hackage-Server
Published
2026-01-16
·
Updated
2026-01-16
None
No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
Hackage package and doc upload stored XSS vulnerability
Author: Fraser Tweedale (Haskell SRT)
Executive summary
A critical XSS vulnerability affected hackage-server and
hackage.haskell.org. HTML and JavaScript files provided in source
packages or via the documentation upload facility were served
as-is on the main hackage.haskell.org domain. As a consequence,
when a user with latent HTTP credentials browses to the package
pages or documentation uploaded by a malicious package maintainer,
their session can be hijacked to upload packages or
documentation, amend maintainers or other package metadata, or
perform any other action the user is authorised to do.This issue was discovered and reported to the Haskell Security
Response Team (SRT) in June 2024. Remediations were progressively
developed and deployed throughout 2025. The known issues have
been fully mitigated on
hackage.haskell.org as of January 2026.The mitigations involve serving user content from a sister domain.
In the case of
hackage.haskell.org, this domain is
hackage-content.haskell.org.Operators of other hackage-server instances should update to the
master branch from the upstream repository
(https://github.com/haskell/hackage-server; commit
9a1887607d9b8d1a3b8b02c990ee144c0d402b79 or later), and configure
the user content domain (new flag --user-content-uri).Scope of the issue
Package documentation uploads
Any Hackage user can upload documentation bundles for the packages
they own. Typically those are prepared by Haddock, but they may be
customised or modified. Malicious code can be delivered in several
ways:
- In JavaScript files loaded by an HTML page;
- In
<script>tags on an HTML page; - In action attributes (e.g.
onclick) on an HTML page.
quick-jump JavaScript
In addition to the supplied HTML pages, parts of the uploaded
documentation bundle are referenced from the main package page (and
candidate pages)—in particular,
quick-jump.min.js, which
implements the "quick jump" feature, and the corresponding CSS file
(CSS can also present an XSS risk). These files are included by the
following templates:datafiles/templates/Html/package-page.html.stdatafiles/templates/Html/candidate-page.html.st
It is loaded via a
<script> tag:html
<script src="$doc.baseUrl$/quick-jump.min.js" type="text/javascript"></script>Source tarball browsing
HTML content in the source package is served as
text/html or
application/xhtml+xml, depending on file extension. The browser
renders the page and executes scripts without restriction. The same
scope of exploitation arises as for documentation uploads.Impact
Malicious scripts can use latent HTTP credentials in the browser to
perform any action the user is authorised to do, without user
interaction. This could include uploading new package versions,
editing packaging metadata, adding new maintainers, and more.
Additionally, malicious scripts and HTML could present a counterfeit
login form to the user, tricking the user into divulging their
credentials. The script can then abuse the credentials in the same
way as the latent credential scenario.
- CVSS vector string: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L
- CVSS score: 9.9 (Critical)
Mitigations
This section describes the code and configuration changes to
mitigate the issues.
User content domain
hackage-server was updated to serve user-uploaded content from a
separate DNS domain. This includes package documentation (excluding
the main package description) and source tarball browsing, for both
published and candidate packages.
For the relevant resources, requests on the main domain are
redirected to the user content domain via an HTTP 301 ("Moved
Permanently") response status.
Doc and source tarballs uploaded prior to the deployment of these
mitigations are exempted from the redirection, and remain accessible
via the main domain (this may be changed in the future).
Alternative approaches considered:
- Serving HTML from the source tarball with
Content-Type: text/plainwould prevent the browser from interpreting them as HTML and executing inline or referenced scripts. But several packages have custom doc bundles uploaded, offering a rich documentation experience to their users. Therefore, changing this behaviour would surprise and probably disappoint many users.
quick-jump: reject unrecognised JavaScript and CSS
A small number of versions of
quick-jump.min.js and
quick-jump.css have appeared in official releases of of the
Haddock documentation builder program. hackage-server matches the
SHA-256 digests of the files in the doc bundle against the list of
"known good" files. If there is no match, hackage-server refuses
to serve the file (403 Forbidden).The digest lists are currently hard-coded; the initial values are
mentioned at the end of this document. The list needs to be updated
whenever the official Haddock quick-jump implementation changes.
Alternative approaches considered:
-
Using Subresource Integrity (SRI) to limit to known-good hashes. This would require the same amount of development and maintenance overhead whilst depending on browser implementation for enforcement.
-
Ignoring the quick-jump implementation from the doc bundle and serving a single "golden" implementation for all packages. Because quick-jump reads the generated
doc-index.jsonthis approach ran the risk of breaking the feature on older (or newer) uploads if the format of the file changes. Formally specifying thedoc-index.jsonwould allow the quick-jump feature to be evolved and improved to bring benefits to all packages and reduce security risks.
There was considerable debate between the digest allow-list and
"golden" approaches. The hackage-server maintainers had the final
say, and the SRT is satisfied that the chosen approach resolves the
security issues.
Acknowledgements
- Zubin Duggal reported the issue in documentation uploads.
- Duncan Coutts noticed that the issue also affects source tarball browsing.
- Gershom Bazerman and Janus Troelsen implemented the
mitigations, and Gershom handled redeploys of the
hackage.haskell.orgservice. - Fraser Tweedale verified and analysed the issue, and coordinated the security response.
Appendix A.1. Known-good variants of quick-jump.min.js
This appendix records known variants of
quick-jump.min.js from the
GHC and Haddock repositories. The commit ID, Git object (short) ID,
and SHA-256 digests are noted. The SHA-256 digests can be used with
Subresource Integrity (SRI) or server-side checks to prevent
delivery or execution of unrecognised script content.From https://gitlab.haskell.org/ghc/haddock.git—master branch
commit: e99aefb50ca63e2dbcc95841efbb53cea90151d8 (Sep 23 2017)
object: c9f2b445b9
sha256: e1da96b0d7ab3d72cfe3786def923c5af91ba331858852f1f43a1acfc5ee6966
commit: 8e88615a23a9f1980a55bd1b3ef9dcc938d95237 (Oct 10 2017)
object: cb24f8bdea
sha256: a273a3ef19c21032afc5f65d1e09933146f183da906ca9d0b4c285095539e0e7
commit: b4982d87f41d9a4d3f6237bacfd819145723e35b (Oct 30 2017)
object: f22f8f2881
sha256: 8aed621ac2b746751585cbe271631394cacc0e01cca4ef589e11b077b0acd291
commit: 93c1e6eb9e829a66ff213ec076d529ab008880b3 (Dec 16 2017)
object: bfdf04a372
sha256: 4b10c18a7ad35f032e8cdc0d263716a93878bf06d998b1b66dccff06ceeee89d
commit: 59812a09eb69cbf12407206381f4c214987b1efd (Apr 3 2018)
object: c03e083607
sha256: ce86bba43edb0534c0faa2d6d0f504877576c5271321e3fbd9638fd4667384a2
commit: a69311708493efe8524aed0e9d19365f79f2fab3 (Oct 24 2018)
object: 06c35c7454
sha256: 548d676b3e5a52cbfef06d7424ec065c1f34c230407f9f5dc002c27a9666bec4From https://gitlab.haskell.org/ghc/ghc.git—master branch
Note: all of the objects listed above also occur in the GHC repo,
but the commit history is different (as expected).
commit: 7776566531e72c415f66dd3b13da9041c52076aa (Nov 13 2019)
object: 0b0eeb27d1
sha256: 7ca43fc2058574846e032bc5493a0ad4568e4fa14fb58558fbf48d3bd6693e59
commit: 14e554cf682ae975ba356b07672c0f9d465e2a78 (May 24 2024)
object: 06c35c7454
sha256: (seen already)Appendix A.2. Known-good variants of quick-jump.css
This appendix records known variants of
quick-jump.css from the
GHC and Haddock repositories. The commit ID, Git object (short) ID,
and SHA-256 digests are noted. The SHA-256 digests can be used with
Subresource Integrity (SRI) or server-side checks to prevent
delivery or use of unrecognised CSS content.From https://gitlab.haskell.org/ghc/haddock.git—master branch
No changes since integration of haddock into the ghc repo.
From https://gitlab.haskell.org/ghc/ghc.git—master branch
commit: 9511e587701349093cbe3ac7c00f13583820774f (Feb 7 2021)
object: cf10eee4
sha256: 6bd159f6d7b1cfef1bd190f1f5eadcd15d35c6c567330d7465c3c35d5195bc6f
commit: 05ccce6e07731f9788a434d6e06f4cadeff3d6ba (Dec 8 2020)
object: d656f51c
sha256: 6997c223e09b340f5f1bb970c930b458f768a0bbbe787cb87f181820a3d122b3
commit: fa5ec121e2a700137bab8bd48cc30b1e80f58fd4 (Feb 27 2019)
object: 8772809c
sha256: 29fe483bd37ad3feba12f646e9661731127526f246c246b0011b384e11649dff
commit: fc069bf200f930c21f96ddbbec1d7c5c69f8ba72 (Jan 15 2018)
object: 468d8036
sha256: 1d51573b72bc8a7b9b0dda3beffb7882db78d22a37840203f761e3969d915027
commit: 0997eb61803a37803ddb6cf7116eb9db1046b2ce (Oct 10 2017)
object: ede05042
sha256: 59693ef3f0d793031b3af58b214af7884c0f63ce6db659ffd7432cf0aa852b51
commit: d41abb0f606bf5fdbdc0a7bd3758e0c30601b121 (Sep 23 2017)
object: b69903c3
sha256: f95b8b12a8a13dd31add93527e1239fdff6997c7f2396e975e2e415db04b75fb Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Hackage-Server