CVE-2026-46430 — algernon
MEDIUMCVE-2026-46430 is a medium-severity (CVSS 4.3) CWE-668 vulnerability in github.com/xyproto/algernon. A fix is available for github.com/xyproto/algernon — see the affected versions and patch details below.
Algernon: Auto-refresh SSE event server binds to all interfaces by default on Linux/macOS
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-46430.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
CVE-2026-46430 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 381,682 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
github.com/xyproto/algernonReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The SSE event server bound to 0.0.0.0:5553 on Linux/macOS by default because the platform-dependent host default in engine/flags.go:39-46 set host = "" for non-Windows, and utils.JoinHostPort("", ":5553") resolves to ":5553" — a Go http.Server.Addr of ":5553" listens on every interface. On Windows the same code chose "localhost", binding loopback only.
The result was a platform split where the OS Algernon's dev workflow is most often used on (Linux/macOS) got the network-exposed default, and only Windows users got the loopback-safe one. A LAN peer with no developer interaction could connect to <dev-laptop-ip>:5553 and read the file-change stream.
This advisory covers the bind-address default in isolation. The fix is independent of authentication (#2a) and CORS (#2b) — switching the default to loopback can be done without touching either.
Details
Root cause — platform-dependent host default in handleFlags
// engine/flags.go:39-46 (1.17.6)
host := ""
if runtime.GOOS == "windows" {
host = "localhost"
// Default Bolt database file
ac.defaultBoltFilename = filepath.Join(serverTempDir, "algernon.db")
// Default log file
ac.defaultLogFile = filepath.Join(serverTempDir, "algernon.log")
}
// engine/config.go:388-391 (1.17.6, finalConfiguration)
if ac.eventAddr == "" {
ac.eventAddr = utils.JoinHostPort(host, ac.defaultEventColonPort)
}
Result tabulated:
| Platform | host | eventAddr after JoinHostPort | Effective bind |
|---|---|---|---|
| Linux | "" | ":5553" | 0.0.0.0:5553 (all interfaces) |
| macOS | "" | ":5553" | 0.0.0.0:5553 (all interfaces) |
| Windows | "localhost" | "localhost:5553" | 127.0.0.1:5553 (loopback) |
The same host value also governs the main web server bind, so the platform split affects both ports. The web-server bind on Linux/macOS is a separate (defensible) design decision — a server intended to be reachable; the SSE port is not such a service and inherited the same default by accident.
Why this is an independent finding
The fix is a single line: change the default host value, or change the eventAddr default specifically, to "localhost" regardless of platform. No change to authentication or CORS is required to close the network-reach half of the original bundled advisory. A LAN peer can no longer connect — the listener is unreachable from another host — even if the SSE handler still has no authentication and still returns Allow-Origin: *.
PoC (against 1.17.6 on Linux/macOS)
# Operator's laptop on a hotel/cafe/office WiFi:
algernon -a /path/to/project
# => SSE listener bound to 0.0.0.0:5553
# Any peer on the same subnet:
$ curl -sN http://<dev-laptop-ip>:5553/sse
id: 0
data: /path/to/project/secret-notes.md
id: 1
data: /path/to/project/.env.local
No interaction from the developer is required. The peer needs network reach and nothing else.
Impact
- Confidentiality: medium. LAN-bounded continuous information disclosure of filenames and edit timing.
- Integrity: none.
- Availability: none directly.
The CVSS vector uses AV:A (adjacent network) to model the LAN-only reach. The vector for a misconfigured deployment behind a NAT-less or routed network would shift to AV:N and rise to 5.3.
Suggestions to fix
Primary fix — pick localhost as the SSE default on every platform.
// engine/flags.go -- platform-independent default for the event listener
// (keep the existing platform split for the WEB server if desired, but
// not for the event server)
host := "localhost"
Or, more surgically:
// engine/config.go -- finalConfiguration
if ac.eventAddr == "" {
ac.eventAddr = utils.JoinHostPort("localhost", ac.defaultEventColonPort)
}
An operator who genuinely wants LAN-reachable SSE can pass --eventserver 0.0.0.0:5553 explicitly and accept the consequences.
Stronger fix — eliminate the second listener entirely. Mount the SSE handler on the main mux at /sse. The bind address is then whatever the main server uses; there is no second listener and therefore no second bind-address default to get wrong.
Live verification
Audit-host bind check (Windows 10):
$ netstat -an | findstr 5553
TCP 127.0.0.1:5553 0.0.0.0:0 LISTENING
Confirms the Windows default is localhost. The Linux/macOS bind to 0.0.0.0:5553 is documented in the code path above; it was not exercised on the audit machine because the audit host was Windows. A maintainer reproducing on a Linux host would see 0.0.0.0:5553 LISTENING from ss -tlnp.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/xyproto/algernon | all versions | 1.17.7go get github.com/xyproto/algernon@v1.17.7 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/xyproto/algernon, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/xyproto/algernon to 1.17.7 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-46430 is resolved across your whole dependency graph.
Workarounds
Assume what was exposed is already known: rotate any credential, token or key that the affected component could return, restrict the endpoint to callers that genuinely need it, and strip sensitive fields from responses and error output at the boundary rather than relying on the client not to read them.
Frequently Asked Questions
Is CVE-2026-46430 in your dependencies?
Find it across Go, including transitive dependencies.