Hackage: package metadata could run as a browser URL
Hackage is the public archive of Haskell packages, and each package has a page there. A package author supplies details in a metadata file, including a homepage, a bug-report address and a source-repository location. The server turns these values into links on the package's page.
So an author writes https://example.org/mylib, and the page shows a link to it. In the pseudocode, render_package_page does this. It places each value in a link's href attribute, which tells the browser where the link goes.
PackageFromTemplate.hs and package-page.html.st before the fix.render_package_page(package):
desc = read_metadata(package)
links = {
"Home page": desc.homepage,
"Bug tracker": desc.bug_reports,
"Source": desc.source_repo,
}
rows = []
for label, url in links:
if url is empty:
continue
# Nothing reads the scheme of url.
link = anchor(href=url, text=url)
rows.add(label, link)
return fill_template(rows)The weak step is a missing question about the start of the URL. The part before the first colon is the scheme, and it tells the browser what to do with the rest. The scheme https fetches a page, and mailto opens an email program. The scheme javascript runs the rest of the URL as a script in the current page.
So a link target is more than an address. It can be an instruction to the browser. The server never looked at the scheme, so a package's metadata could choose one that runs a script.
Escaping does not help here. Escaping stops a quotation mark in the value from ending the href attribute early. The value still arrives whole, so the browser still reads its scheme. The HTML is correct, and its meaning is still unsafe.
This is stored cross-site scripting. A server saves text from one user and serves it to others, and the text runs as a script in their browsers. A script in a page has the same access as the site's own code. So the browser treats it as part of Hackage.
AISLE reports AI-assisted discovery. The Haskell Security Response Team credits Joshua Rogers of AISLE and confirms deployment of the fix. Its audit of published package versions found no attempts to use the flaw.