VYPR
Moderate severityOSV Advisory· Published Dec 10, 2025· Updated Dec 18, 2025

CVE-2025-65754

CVE-2025-65754

Description

Cross Site Scripting vulnerability in Algernon v1.17.4 allows attackers to execute arbitrary code via injecting a crafted payload into a filename.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Algernon v1.17.4 contains a stored XSS vulnerability that allows arbitrary code execution via crafted filenames in directory listings.

Vulnerability

CVE-2025-65754 describes a Cross-Site Scripting (XSS) flaw in Algernon v1.17.4, a small self-contained web server. The root cause is that filenames from the filesystem are directly inserted into HTML without escaping when rendering directory listings [2][4]. In themes/html.go, the function HTMLLink takes a filename and URL and constructs an anchor tag without sanitizing the text parameter, which contains the filename [4].

Exploitation

An attacker can exploit this vulnerability by creating files on the server filesystem with malicious filenames containing XSS payloads. For example, creating a file named test.txt or document.svg will cause the payload to execute when a user browses the directory listing served by Algernon [4]. The attack does not require authentication if directory listings are publicly accessible, which is the default configuration [1].

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of the victim's browser. This can lead to session hijacking, cookie theft, or defacement of the web application [3][4]. Since Algernon supports file uploads and shared hosting scenarios, the risk is amplified as attackers can plant malicious files directly [4].

Mitigation

The vendor has released a fix in commit cd8832014a624a9aeab60566434c3344135e23f8 that adds input sanitization using the bluemonday policy for theme names, titles, and other user-controlled strings [2]. Users are strongly advised to update to the latest version (≥ 1.17.5 or the patched commit). No workarounds are provided, but disabling directory listing or restricting file uploads could reduce exposure if patching is not immediately possible.

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/xyproto/algernonGo
< 1.17.51.17.5

Affected products

2
  • Xyproto/AlgernonOSV2 versions
    0.2, 0.3, 0.4, …+ 1 more
    • (no CPE)range: 0.2, 0.3, 0.4, …
    • (no CPE)range: = 1.17.4

Patches

1
cd8832014a62

Add extra sanitation / XSS protection, thanks @Bnyt7

https://github.com/xyproto/algernonAlexander F. RødsethNov 13, 2025via ghsa
1 file changed · +43 10
  • themes/html.go+43 10 modified
    @@ -32,13 +32,20 @@ func MessagePage(title, body, theme string) string {
     	return fmt.Sprintf("<!doctype html><html><head><title>%s</title>%s</head><body><h1>%s</h1>%s", title, StyleHead(theme), title, body)
     }
     
    +var policy = bluemonday.UGCPolicy()
    +
     // StyleHead returns contents that goes in "<head>", as bytes.
     // This is either CSS wrapped in a "<style>" tag, or "<link>" tags to CSS and JS.
     func StyleHead(theme string) []byte {
    +
    +	// Sanitize the theme name
    +	theme = policy.Sanitize(theme)
    +
     	var buf bytes.Buffer
     	if theme == "material" {
     		buf.WriteString(MaterialHead())
     	}
    +
     	if strings.HasSuffix(theme, ".css") {
     		buf.WriteString("<style>html { margin: 3em; }</style>")
     		buf.WriteString("<link rel=\"stylesheet\" href=\"" + theme + "\">")
    @@ -53,6 +60,11 @@ func StyleHead(theme string) []byte {
     // MessagePageBytes provides the same functionalityt as MessagePage,
     // but with []byte instead of string, and without closing </body></html>
     func MessagePageBytes(title string, body []byte, theme string) []byte {
    +
    +	// Sanitize the theme and title
    +	theme = policy.Sanitize(theme)
    +	title = policy.Sanitize(title)
    +
     	var buf bytes.Buffer
     	buf.WriteString("<!doctype html><html><head><title>")
     	buf.WriteString(title)
    @@ -67,24 +79,30 @@ func MessagePageBytes(title string, body []byte, theme string) []byte {
     
     // SimpleHTMLPage provides a quick way to build a HTML page
     func SimpleHTMLPage(title, headline, inhead, body, language []byte) []byte {
    +
    +	// Sanitize the title, headline and language
    +	titleString := policy.Sanitize(string(title))
    +	headlineString := policy.Sanitize(string(headline))
    +	languageString := policy.Sanitize(string(language))
    +
     	var buf bytes.Buffer
    -	if len(language) > 0 {
    +	if len(languageString) > 0 {
     		buf.WriteString("<!doctype html><html lang=\"")
    -		buf.Write(language)
    +		buf.WriteString(languageString)
     		buf.WriteString("\">")
     	} else {
     		buf.WriteString("<!doctype html><html>")
     	}
    -	if len(title) > 0 {
    +	if len(titleString) > 0 {
     		buf.WriteString("<head><title>")
    -		buf.Write(title)
    +		buf.WriteString(titleString)
     		buf.WriteString("</title></head>")
     	}
     	buf.Write(inhead)
     	buf.WriteString("<body>")
    -	if len(headline) > 0 {
    +	if len(headlineString) > 0 {
     		buf.WriteString("<h1>")
    -		buf.Write(headline)
    +		buf.WriteString(headlineString)
     		buf.WriteString("</h1>")
     	}
     	buf.Write(body)
    @@ -94,6 +112,11 @@ func SimpleHTMLPage(title, headline, inhead, body, language []byte) []byte {
     // HTMLLink builds an HTML link given the link text, the URL to a file/directory
     // and a boolean that is true if the given URL is to a directory.
     func HTMLLink(text, url string, isDirectory bool) string {
    +
    +	// Sanitize the link text and the link URL
    +	text = policy.Sanitize(text)
    +	url = policy.Sanitize(url)
    +
     	// Add a final slash, if needed
     	if isDirectory {
     		text += "/"
    @@ -104,6 +127,10 @@ func HTMLLink(text, url string, isDirectory bool) string {
     
     // StyleAmber modifies Amber source code so that a link to the given stylesheet URL is added
     func StyleAmber(amberdata []byte, url string) []byte {
    +
    +	// Sanitize the URL
    +	url = policy.Sanitize(url)
    +
     	// If the given url is not already mentioned and the data contains "body"
     	if !bytes.Contains(amberdata, []byte(url)) && bytes.Contains(amberdata, []byte("html")) && bytes.Contains(amberdata, []byte("body")) {
     		// Extract one level of indendation
    @@ -122,6 +149,10 @@ func StyleAmber(amberdata []byte, url string) []byte {
     
     // StyleHTML modifies HTML source code so that a link to the given stylesheet URL is added
     func StyleHTML(htmldata []byte, url string) []byte {
    +
    +	// Sanitize the URL
    +	url = policy.Sanitize(url)
    +
     	// If the given url is not already mentioned and the data contains "body"
     	if !bytes.Contains(htmldata, []byte(url)) && bytes.Contains(htmldata, []byte("body")) {
     		if bytes.Contains(htmldata, []byte("</head>")) {
    @@ -152,9 +183,11 @@ func InsertDoctype(htmldata []byte) []byte {
     
     // NoPage generates a HTML page for when a file is not found
     func NoPage(filename, theme string) []byte {
    -	// Sanitize the filename
    -	policy := bluemonday.UGCPolicy()
    -	sanitizedFilename := policy.Sanitize(filename)
    +
    +	// Sanitize the filename and the theme name
    +	filename = policy.Sanitize(filename)
    +	theme = policy.Sanitize(theme)
    +
     	// Return a HTML page
    -	return MessagePageBytes("Not found", []byte("File not found: "+sanitizedFilename), theme)
    +	return MessagePageBytes("Not found", []byte("File not found: "+filename), theme)
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.