Skip to content

Commit 5309cf6

Browse files
committed
Patched Discloure
1 parent 4ff1e48 commit 5309cf6

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

posts/algernon-four-findings.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
*Author: [Dredsen](https://dredsen.github.io/)*
2+
3+
---
4+
5+
Algernon is a small, self-contained web server written in Go. You point it at a directory and it serves whatever's there: Markdown, Lua, templates, static files, the lot. The pitch is "drop a single binary in a folder and you've got a working site." It's the kind of tool people reach for when they want zero-setup file serving without standing up nginx or a framework and just want something thats simple and works out of the box.
6+
7+
I decided to test out using AI Fuzzing with Qwen 3.6 35B with a custom harness on the main branch of Algernon 1.17.6 and ended up with four advisories. None of them require authentication, all of them work on a default install with no flags, and three of them are reachable just by running the documented quickstart inside a project folder.
8+
9+
---
10+
11+
## What I found
12+
13+
### 1. `handler.lua` discovery walks above the server root
14+
15+
When Algernon serves a directory, it looks for a `handler.lua` script to use as the request handler. If the current directory doesn't have one, the search walks **upward** through parent directories, past the configured server root, all the way toward the filesystem root.
16+
17+
The first `handler.lua` it finds gets loaded into the Lua interpreter with the full Algernon API exposed - file system, shell, HTTP client, database drivers. Anyone who can write a file at any ancestor path on disk gets pre-authenticated code execution on the next request.
18+
19+
Plant a `handler.lua` one directory above the served root and any unauthenticated request triggers it:
20+
21+
```
22+
$ ./algernon site/
23+
$ curl http://127.0.0.1:8080/
24+
=== PWNED via parent handler.lua ===
25+
Hostname: DESKTOP-4RLE5YR
26+
```
27+
28+
The handler that lives one directory **above** `site/` (and was never part of the served tree) executed inside the Algernon process and its output became the HTTP 200 response body.
29+
30+
### 2. Auto-refresh SSE listener leaks edits across the network
31+
32+
The `-a` / `--autorefresh` flag spins up a second HTTP listener that streams a Server-Sent-Events feed of every filename the developer is editing. That listener:
33+
34+
- binds to all interfaces by default on Linux and macOS,
35+
- sets `Access-Control-Allow-Origin: *` on every response,
36+
- has no authentication and is not gated by the main permission system.
37+
38+
Anything on the same network can subscribe to a live transcript of your editor activity. Any web page you open in a browser can subscribe cross-origin. The leak is filenames and timing, not file contents, but it's still a real-time map of your project layout to anyone who asks.
39+
40+
```
41+
$ curl -H "Origin: http://evil.example" http://127.0.0.1:5553/sse
42+
HTTP/1.1 200 OK
43+
Access-Control-Allow-Origin: *
44+
Content-Type: text/event-stream
45+
46+
id: 0
47+
data: C:\Users\xbox\...\site\.env.local
48+
```
49+
50+
The stream emits **absolute paths**, so it also leaks the developer's username, drive letter, and directory layout. No `Authorization`, no cookie, no token, and the `Origin: http://evil.example` header was happily reflected as a wildcard.
51+
52+
### 3. Default install serves dotfiles, including `.git` and `.env`
53+
54+
The documented quickstart is `algernon .` - point it at the current directory. If that directory is a git repository, the server happily serves `.git/config`, `.git/HEAD`, pack files, anything else under `.git/`. Same for `.env`, `.ssh`, `.htpasswd`, anything starting with a dot.
55+
56+
There's an opt-in `ignore.txt` mechanism, but it only hides files from the directory listing - the file handler itself still serves them when the URL is requested directly. So patterns in `ignore.txt` cover one half of the exposure and leave the other half wide open.
57+
58+
```
59+
$ curl http://127.0.0.1:8080/.env
60+
DATABASE_URL=postgres://app:hunter2@db.internal:5432/prod
61+
SECRET_KEY_BASE=fake-jwt-signing-secret-for-poc-only
62+
63+
$ curl http://127.0.0.1:8080/.git/config
64+
[core]
65+
repositoryformatversion = 0
66+
[remote "origin"]
67+
url = git@github.com:internal/private-repo.git
68+
```
69+
70+
Both came back unauthenticated. The `.env` was on the `ignore.txt` block-list and still served - the listing hid it, the file handler didn't care.
71+
72+
### 4. Single-file mode forces debug mode
73+
74+
Algernon has a "single file" shortcut: `algernon foo.po2` or `algernon page.html` to demo one file without setting up a directory. This mode unconditionally sets `debugMode = true`, no opt-out.
75+
76+
`debugMode` turns on the pretty error page, which on any script or template error dumps the full server-side source of the file being rendered, line-by-line, with the absolute filesystem path. If the served file contains secrets (API keys hardcoded into a Lua script, database credentials in a template), a single malformed request that triggers an error is enough to leak them.
77+
78+
```
79+
$ ./algernon page.po2 # page.po2 references data.lua, which has a parse error
80+
$ curl http://127.0.0.1:8080/
81+
<title>Lua Error</title>
82+
...
83+
Contents of data.lua:
84+
local SECRET = "sk-LEAKCANARY-DATALUA-PRIVATE"
85+
this is intentionally bad lua
86+
```
87+
88+
The `SECRET` from `data.lua` ended up in the HTML response of an unauthenticated `GET /`. No debug flag was passed - single-file mode turned it on by itself.
89+
90+
---
91+
## Disclosure
92+
93+
All four were reported privately to the maintainer and patched within 24 hours. Thanks to [xyproto](https://github.com/xyproto) for the quick turnaround, [Here are the in-depth reports for CVE/GHSA](https://github.com/xyproto/algernon/security).

posts/index.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
[
2+
{
3+
"slug": "algernon-four-findings",
4+
"title": "Four Findings in Algernon 1.17.6 with AI fuzzing",
5+
"date": "2026-05-12",
6+
"summary": "Using Qwen 3.6 35B with a custom harness to find bugs on Algernon web server and finding four pre-auth issues."
7+
},
28
{
39
"slug": "alicesoft-jst-timezone-fix",
410
"title": "Patching Alicesoft Games So They Run Outside Japan Time",

0 commit comments

Comments
 (0)