Changelog / v1.1.3

OpenYak 1.1.3 — Critical CSRF → RCE Fix (GHSA-ccxp-q2w5-27jw / CVE-2026-46409)

Apr 24, 2026 (publicly disclosed May 21, 2026) by OpenYak Team

Advisory at a glance

GHSA-ccxp-q2w5-27jw / CVE-2026-46409 — Unauthenticated Cross-Site Request Forgery (CSRF) chaining to Remote Code Execution (RCE) in the local HTTP API of the OpenYak desktop app. Severity Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H, score 9.6). CWEs: 352, 306, 346, 94, 942. Affected: all releases up to and including v1.1.2. Patched in v1.1.3 — every version since (v1.1.4 → v1.1.10) carries the fix forward.

github.com/openyak/openyak/security/advisories/GHSA-ccxp-q2w5-27jw

The attack chain

The OpenYak desktop backend binds an HTTP API to 127.0.0.1:<random port> for the Tauri shell to talk to. Before v1.1.3, that server had no server-side Origin validation, no loopback authentication, no Content-Type enforcement, and a wildcard CORS policy (allow_origins=["*"]). Any web page a user visited while OpenYak was running could issue cross-origin requests directly to this local server — the browser acted as a proxy into loopback, bypassing OS-level network isolation. Chained, this meant a single malicious page could (1) discover the local OpenYak instance, (2) authenticate-by-default to its mutating endpoints, (3) hit the build-agent endpoint with permission_presets.bash=true to execute arbitrary shell commands, and (4) read chat history (which routinely contains pasted credentials, source code, and client data) and account PII — with no user interaction beyond opening the page. Default port unpredictability is not a defense (any malicious page can port-scan loopback from JavaScript), and Chrome Private Network Access is not implemented in Firefox or several mobile browsers and has had documented bypasses, so we did not rely on it.

What the fix does

A new pure-ASGI CsrfProtectionMiddleware rejects mutating requests (POST / PUT / PATCH / DELETE) whose Origin (or Referer fallback) is not in an explicit allowlist; the literal "null" origin is rejected outright. Body Content-Type is restricted to application/json, multipart/form-data, and application/x-www-form-urlencoded. CORS narrowed from allow_origins=["*"] to a regex matching only the OpenYak frontend (Tauri shell + loopback). The authentication middleware is now deny-by-default: a new endpoint is authenticated unless explicitly added to the public allowlist — much harder to forget than per-route opt-in. Per-run session-token files are written 0600 so a different local user on a shared host cannot read them. The tunnel-URL allowlist is dynamic, so cloudflared tunnel restarts swap the active origin atomically through an on_url_change callback. Native API consumers — Tauri shell, mobile companion, curl, CI scripts — send no Origin and continue to work unchanged.

Test coverage

47 unit tests cover the Origin allowlist, hostname-spoofing variants (subdomain tricks, userinfo, decimal/hex-encoded IPs, punycode), IPv6 loopback, Referer precedence, case-insensitive scheme/host, Content-Type enforcement, and CORS preflight behavior. The fix is wired as a single global ASGI middleware, so non-/api/* routes — including the /v1/* OpenAI-compatible surface, which earlier patch drafts almost missed because they were mounted at root rather than under /api/* — inherit the same protection without a separate path allowlist.

Credit

Reported responsibly by Arturo Melgarejo Galindo (@Arturo0x90) on April 22, 2026 with a complete report — proof-of-concept video, written four-stage chain analysis, CVSS justification, and proposed remediation. Three rounds of review on the private patch fork hardened the fix substantially: catching the /v1/* path-allowlist gap, pointing out that defense-in-depth Origin checks don't replace authentication as the primary control, and flagging that the literal "null" origin needed an explicit reject rather than relying on allowlist mismatch. Coordinated disclosure handled professionally throughout. Thank you, Arturo.

Upgrading and disclosure note

If you are on v1.1.0 or later, you have already auto-updated past v1.1.3 — every release since carries the fix. If you are on v1.1.2 or earlier, please update to the current release (v1.1.10) immediately, either through Help → Check for Updates or by downloading the installer from open-yak.com/download. The fix shipped Apr 24, 2026; public disclosure was originally scheduled for May 8 with the standard two-week cooling window. We missed that calendar reminder and published on May 21 instead — apologies to the reporter and to the security community for the slip.