{"id":"GHSA-6vgg-xhvh-38ff","summary":"nebula-mesh: POST /api/v1/hosts/{id}/mobile-bundle response lacks Cache-Control: no-store","details":"`internal/api/mobile_bundle.go:62-66` sets only `Content-Type: application/yaml`. The Web-UI sibling at `internal/web/handlers.go:1316-1321` sets `Cache-Control: no-store`, `Pragma: no-cache`, `Expires: 0`, `X-Content-Type-Options: nosniff` — and has a test asserting it. The API path was missed.\n\n## Affected\nAll released versions up to v0.3.0.\n\n## Threat model\nThe endpoint returns a freshly minted X25519 private key inline. Without `no-store`, any intermediary proxy or CDN that caches `200 OK` YAML responses retains the private key for its cache TTL. Same applies to browser disk cache for direct API hits. Combined with the cross-tenant authz advisory (critical), even a corrected authz layer would still leak via cache after fix.\n\n## Suggested fix\nCopy the four headers from the Web sibling:\n\n```go\nw.Header().Set(\"Content-Type\", \"application/yaml; charset=utf-8\")\nw.Header().Set(\"Cache-Control\", \"no-store\")\nw.Header().Set(\"Pragma\", \"no-cache\")\nw.Header().Set(\"Expires\", \"0\")\nw.Header().Set(\"X-Content-Type-Options\", \"nosniff\")\n```\n\nMirrors `internal/web/handlers.go:1316-1321`. Add a parallel test to the existing web-side coverage.\n\n## Suggested patch\n\nVerified locally: `go vet`, `go test -race -count=1 ./...`, `golangci-lint v2.12` all clean.\n\n```diff\ndiff --git a/internal/api/mobile_bundle.go b/internal/api/mobile_bundle.go\nindex fc09da0..73152eb 100644\n--- a/internal/api/mobile_bundle.go\n+++ b/internal/api/mobile_bundle.go\n@@ -58,8 +58,15 @@ func (s *Server) handleMobileBundle(w http.ResponseWriter, r *http.Request) {\n \t\treturn\n \t}\n \n-\t// Return YAML bundle with proper content-type\n+\t// Return YAML bundle with proper content-type. The bundle inlines a\n+\t// freshly-minted X25519 private key, so suppress every layer of cache\n+\t// between server and operator (intermediate proxies/CDNs, browser disk\n+\t// cache). Mirrors the Web-UI sibling at internal/web/handlers.go.\n \tw.Header().Set(\"Content-Type\", \"application/yaml; charset=utf-8\")\n+\tw.Header().Set(\"Cache-Control\", \"no-store\")\n+\tw.Header().Set(\"Pragma\", \"no-cache\")\n+\tw.Header().Set(\"Expires\", \"0\")\n+\tw.Header().Set(\"X-Content-Type-Options\", \"nosniff\")\n \tw.WriteHeader(http.StatusOK)\n \tif _, err := w.Write(bundle); err != nil {\n \t\ts.logger.Error(\"write mobile bundle response\", \"error\", err)\ndiff --git a/internal/api/mobile_bundle_test.go b/internal/api/mobile_bundle_test.go\nindex dcb8cd9..da08b01 100644\n--- a/internal/api/mobile_bundle_test.go\n+++ b/internal/api/mobile_bundle_test.go\n@@ -52,6 +52,19 @@ func TestHandleMobileBundle_Success(t *testing.T) {\n \t\tt.Errorf(\"Content-Type = %q, want 'application/yaml; charset=utf-8'\", ct)\n \t}\n \n+\t// Bundle inlines a private key — every cache between server and operator\n+\t// must drop the response. Mirrors the Web-UI sibling's headers.\n+\tfor header, want := range map[string]string{\n+\t\t\"Cache-Control\":         \"no-store\",\n+\t\t\"Pragma\":                \"no-cache\",\n+\t\t\"Expires\":               \"0\",\n+\t\t\"X-Content-Type-Options\": \"nosniff\",\n+\t} {\n+\t\tif got := w.Header().Get(header); got != want {\n+\t\t\tt.Errorf(\"%s = %q, want %q\", header, got, want)\n+\t\t}\n+\t}\n+\n \t// Verify body is valid YAML with expected keys\n \tvar yamlData map[string]interface{}\n \tif err := yaml.Unmarshal(w.Body.Bytes(), &yamlData); err != nil {\n```","aliases":["GO-2026-5191"],"modified":"2026-06-25T19:56:40.593877200Z","published":"2026-06-12T18:30:09Z","database_specific":{"github_reviewed_at":"2026-06-12T18:30:09Z","nvd_published_at":null,"cwe_ids":["CWE-525"],"severity":"LOW","github_reviewed":true},"references":[{"type":"WEB","url":"https://github.com/juev/nebula-mesh/security/advisories/GHSA-6vgg-xhvh-38ff"},{"type":"WEB","url":"https://github.com/forgekeep/nebula-mesh/commit/c13d5b2c013b4b323bc0c87a6ecc6afba6384ee5"},{"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":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-6vgg-xhvh-38ff/GHSA-6vgg-xhvh-38ff.json","last_known_affected_version_range":"\u003c= 0.3.1"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"}]}