{"id":"GHSA-273q-qgh5-wrj6","revision":"e9da4b44891742e1ba1f8d581c02a265","records":[{"revision":"e9da4b44891742e1ba1f8d581c02a265","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-273q-qgh5-wrj6","aliases":["CVE-2026-47725","GO-2026-5049"],"title":"nebula-mesh's web UI lacks CSRF tokens on /ui/* mutating endpoints","description":"Every `/ui/*` POST / PUT / PATCH / DELETE route processes the request as soon as the session cookie validates. `SameSite=Lax` on the session cookie prevents most cross-site form submits but does not protect:\n\n- top-level form-submit navigations from third-party pages (some browsers still send Lax cookies on top-level POSTs)\n- same-registrable-domain attackers (sibling-subdomain XSS, subdomain takeover)\n- the `GET /ui/logout` route, which a third-party `<img src=\".../ui/logout\">` can force-trigger\n\nThe admin UI signs CA certificates, mints API keys, rotates / retires / deletes CAs, disables operators, and changes server settings. CSRF here is a real privilege escalation, not just annoyance.\n\n## Affected\nAll released versions up to v0.3.2.\n\n## Suggested fix\nDouble-submit cookie: a 32-byte `crypto/rand` token in a non-HttpOnly `_csrf` cookie, echoed in either `X-CSRF-Token` (htmx) or a `_csrf` form field (HTML forms). Compared in constant time. Rotated on every privilege transition (`Login`, OIDC `StartAuthenticatedSession`, `CompleteTwoFactor`, `Logout`) so pre-auth fixation cannot survive promotion. Rejections audit-logged as `ui.csrf.rejected` with reason; response body stays opaque.\n\n`/ui/logout` becomes POST so it is no longer reachable via `<img>` tags.\n\nFix coordinates with the Secure-cookie advisory disclosed concurrently — the `_csrf` cookie inherits the same `Secure`-attribute derivation.\n\n## Reproducer\nWith an authenticated operator session in browser tab A, open the following minimal HTML in any other tab:\n\n```html\n<form action=\"https://nebula.example.com/ui/cas/{ca-id}/delete\" method=\"POST\">\n  <button>Click for free puppy</button>\n</form>\n```\n\nClick. The CA is deleted — the server processes the POST because the session cookie is automatically attached and there is no other check. The same trick works for force-rotate, retire, mint API keys, disable operators, etc.\n\nAlternative force-logout: `<img src=\"https://nebula.example.com/ui/logout\">` placed on an attacker's page logs out any visiting authenticated operator. No interaction required.\n\n## Notes\n- Multipart and JSON endpoints don't exist in the current UI surface. Future additions must rely on the header path because `r.PostFormValue` only reads `application/x-www-form-urlencoded` bodies. The middleware's package comment documents this.\n- The patch assumes nebula-mgmt is the sole authority on its registrable domain. A compromised sibling subdomain can still set parent-domain cookies and forge matches; SameSite=Lax does not prevent that. Documented in the patch.","state":0,"publishedAt":"2026-06-08T23:09:21+00:00","modifiedAt":"2026-06-17T00:26:22.8966404+00:00","affected":[{"ecosystem":"Go","name":"github.com/juev/nebula-mesh","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.3.3"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/juev/nebula-mesh/security/advisories/GHSA-273q-qgh5-wrj6","https://github.com/juev/nebula-mesh"],"sourceUrl":"https://github.com/advisories/GHSA-273q-qgh5-wrj6","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-273q-qgh5-wrj6","identifiers":["GHSA-273q-qgh5-wrj6","CVE-2026-47725","GO-2026-5049"]},"retained":false,"historicalAffected":[]}],"coverage":[]}