{"id":"GHSA-9pg3-25fq-p6cc","summary":"nebula-mesh: Newly-minted operator API key exposed in redirect URL (Referer, history, proxy logs)","details":"`internal/web/operators.go:251` — after `handleOperatorCreateAPIKey` mints a fresh 32-byte bearer token, the redirect points the operator's browser at:\n\n    /ui/operators/\u003cid\u003e?new_key=\u003craw-token\u003e&key_name=\u003cname\u003e\n\nThe raw API key ends up:\n- in the browser's URL history\n- in the `Referer` header on every cross-origin asset the detail page loads (any third-party SVG/CSS/JS resource the layout pulls in)\n- in any reverse-proxy or load-balancer access log on the path (nginx default `combined` log captures the query string)\n- in any structured log sink the operator's local browser-history backup tool ships out\n\n`Authorization: Bearer \u003ctoken\u003e` headers go through the same hops without these problems because access logs typically don't capture request headers and the browser doesn't replay headers cross-origin.\n\nSame handler also appends `name` (`r.FormValue(\"name\")`) to the query string without `url.QueryEscape`, so an `&` in the operator-supplied key name corrupts query parsing and a `\\r\\n` in older proxies could split response headers.\n\n## Affected\nAll released versions up to v0.3.1.\n\n## Reproducer\nAs admin, create an API key via `/ui/operators/\u003cid\u003e/api-keys` (form POST). The 303 Location header carries the raw token in the query string. Open browser DevTools → Network → response headers; or check the reverse-proxy access log; or check the operator-detail page's `Referer`-emitting fetches.\n\n## Suggested fix\nStash the raw key in a one-shot server-side flash storage (e.g., a row in `operator_sessions` keyed by session token, with a `one_shot_token` column and `consumed_at`) or in a short-lived signed cookie. Render the key once inline on the detail page after the redirect, and clear the storage on render. Pattern mirrors the recovery-codes display in the TOTP flow.\n\nIf the flash-storage refactor is too invasive, the minimal fix is to render the key inline via a `POST` → `200 OK with HTML` (no redirect), losing the post-redirect-get idiom but eliminating the URL exposure.\n\nAlso fix `name` query encoding with `url.QueryEscape` regardless of which fix shape lands.\n\n## CVSS estimate\nAV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N — 5.5 (medium). AV:L because realistic exploit requires log-read access on shared infrastructure (proxy, CDN, browser-history backup) the operator's session touches.","aliases":["CVE-2026-47768","GO-2026-5294"],"modified":"2026-06-25T19:56:25.326506795Z","published":"2026-06-10T22:13:45Z","database_specific":{"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-06-10T22:13:45Z","nvd_published_at":null,"cwe_ids":["CWE-116","CWE-532","CWE-598"]},"references":[{"type":"WEB","url":"https://github.com/juev/nebula-mesh/security/advisories/GHSA-9pg3-25fq-p6cc"},{"type":"PACKAGE","url":"https://github.com/juev/nebula-mesh"}],"affected":[{"package":{"name":"github.com/juev/nebula-mesh","ecosystem":"Go","purl":"pkg:golang/github.com/juev/nebula-mesh"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.3.2"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 0.3.1","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-9pg3-25fq-p6cc/GHSA-9pg3-25fq-p6cc.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"}]}