VYPR
High severity8.2NVD Advisory· Published May 26, 2026· Updated May 26, 2026

CVE-2026-48126

CVE-2026-48126

Description

Algernon is a small self-contained pure-Go web server. Prior to 1.17.8, when algernon is started with --domain (or --letsencrypt, which silently turns on --domain at engine/flags.go:372), the request handler resolves the served directory by joining the configured --dir with the value of the client-supplied Host header. The join is performed by filepath.Join with no validation, so a Host: .. header walks one level above the document root. Subsequent file resolution then exposes everything in that parent directory — arbitrary file read, full directory listing, and, if any .lua file is present, server-side Lua execution. This vulnerability is fixed in 1.17.8.

AI Insight

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

Path traversal in Algernon <1.17.8 when --domain mode is active lets an attacker read arbitrary server files and execute Lua scripts via a crafted Host header.

Vulnerability

Algernon versions prior to 1.17.8 contain a path traversal vulnerability when the --domain flag (or --letsencrypt, which implicitly enables --domain) is active. The request handler in engine/handlers.go constructs the served directory by calling filepath.Join(servedir, utils.GetDomain(req)). The GetDomain function (utils/web.go) returns the client-supplied Host header verbatim if it lacks a port, and filepath.Join normalizes the resulting path without validation. A Host: .. header therefore resolves one directory level above the configured document root, exposing parent-directory contents. The affected versions are 1.17.7 and earlier [1].

Exploitation

An attacker only needs to send an HTTP request with a Host header containing .. (and optionally a port, though the fallback path yields the same result) to the Algernon server. No authentication is required. The server's filepath.Join normalizes the path, and utils.URL2filename does not sanitize the base directory, so subsequent file resolution uses the attacker-controlled base. For directory listings, the DirPage handler enumerates the parent directory; for file requests, FilePage reads any file within that parent. If a .lua file exists in the parent, the server executes it server-side [1].

Impact

Successful exploitation grants an unauthenticated attacker arbitrary file read (including configuration files, source code, or secrets), full directory listing of the parent directory, and, if any .lua script is present, server-side Lua code execution with the privileges of the algernon process. The confidentiality, integrity, and availability impact is high [1].

Mitigation

The vulnerability is fixed in Algernon 1.17.8, released on the same date as this advisory. Users should upgrade to 1.17.8 or later. No workaround is available for versions below 1.17.8 if --domain or --letsencrypt mode is required [1].

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

Affected products

2
  • Xyproto/Algernoninferred2 versions
    <1.17.8+ 1 more
    • (no CPE)range: <1.17.8
    • (no CPE)range: <1.17.8

Patches

1
95e2ddd38950

Fix path traversal when --domain is used, thanks @fg0x0

https://github.com/xyproto/algernonAlexander F. RødsethMay 21, 2026Fixed in 1.17.8via llm-release-walk
1 file changed · +7 1
  • engine/handlers.go+7 1 modified
    @@ -528,7 +528,13 @@ func (ac *Config) RegisterHandlers(mux *http.ServeMux, handlePath, servedir stri
     
     		// Look for the directory that is named the same as the host
     		if addDomain {
    -			servedir = filepath.Join(servedir, utils.GetDomain(req))
    +			domain := utils.GetDomain(req)
    +			// Reject Host header values that could escape the document root via path traversal
    +			if domain == "" || strings.ContainsAny(domain, "/\\") || strings.Contains(domain, "..") {
    +				http.Error(w, "Bad Request", http.StatusBadRequest)
    +				return
    +			}
    +			servedir = filepath.Join(servedir, domain)
     		}
     
     		urlpath := req.URL.Path
    

Vulnerability mechanics

Root cause

"Missing input validation on the Host header allows path traversal via filepath.Join when --domain mode is enabled."

Attack vector

An unauthenticated remote attacker sends an HTTP request with a Host header set to ".." to an algernon server started with --domain or --letsencrypt [ref_id=1]. The server calls filepath.Join(servedir, utils.GetDomain(req)) with no validation, so the ".." value resolves the served directory to the parent of the configured document root [ref_id=1]. Subsequent file resolution then exposes arbitrary file reads, directory listings, and — if any .lua file exists in the parent directory — server-side Lua execution leading to shell command execution [ref_id=1]. No authentication or special network position is required; the attack works over plain HTTP.

Affected code

The vulnerable code is in engine/handlers.go, function RegisterHandlers, where filepath.Join(servedir, utils.GetDomain(req)) is called without validating the Host header [ref_id=1]. The GetDomain function in utils/web.go returns the Host header verbatim when net.SplitHostPort fails (e.g. for a value like "..") [ref_id=1]. The URL2filename function in utils/files.go only sanitizes the URL path, not the dirname parameter [ref_id=1].

What the fix does

The patch adds a validation check before the filepath.Join call in engine/handlers.go [patch_id=2565391]. It rejects Host header values that are empty, contain "/" or "\\", or contain "..", returning HTTP 400 Bad Request [patch_id=2565391]. This prevents an attacker from using the Host header to escape the document root via path traversal, closing the arbitrary file read, directory listing, and Lua RCE attack paths described in the advisory [ref_id=1].

Preconditions

  • configAlgernon must be started with --domain or --letsencrypt flag (--letsencrypt silently enables --domain)
  • networkAttacker must be able to send HTTP requests to the server
  • authNo authentication required
  • inputAttacker controls the Host header value in the HTTP request

Reproduction

Build the affected version: `git clone https://github.com/xyproto/algernon && cd algernon && go build -o /tmp/algernon .`. Set up test files: `WORK=$(mktemp -d) && mkdir -p $WORK/site && echo '<h1>public</h1>' > $WORK/site/index.html && echo 'TOP-SECRET FROM PARENT DIR' > $WORK/SECRET.txt`. Start server: `/tmp/algernon --httponly --dir $WORK/site --addr :7799 --server -n --domain --nolimit &`. Read arbitrary file: `curl -H 'Host: ..' http://127.0.0.1:7799/SECRET.txt`. List parent directory: `curl -H 'Host: ..' http://127.0.0.1:7799/`. For Lua RCE, create `$WORK/pwn.lua` with Lua code calling `run3("id; uname -a")` and request it: `curl -H 'Host: ..' http://127.0.0.1:7799/pwn.lua` [ref_id=1].

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

References

1

News mentions

0

No linked articles in our index yet.