---
id: GHSA-6vgg-xhvh-38ff
title: >-
  nebula-mesh: POST /api/v1/hosts/{id}/mobile-bundle response lacks
  Cache-Control: no-store
summary: >-
  nebula-mesh: POST /api/v1/hosts/{id}/mobile-bundle response lacks
  Cache-Control: no-store
severity: low
cwe:
  - CWE-525
vendor: juev
product: github.com/juev/nebula-mesh
ecosystem: go
affected:
  - github.com/juev/nebula-mesh <= 0.3.1
patched:
  - github.com/juev/nebula-mesh 0.3.2
published: '2026-06-12'
updated: '2026-06-12'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-6vgg-xhvh-38ff'
references:
  - url: >-
      https://github.com/juev/nebula-mesh/security/advisories/GHSA-6vgg-xhvh-38ff
  - url: >-
      https://github.com/forgekeep/nebula-mesh/commit/c13d5b2c013b4b323bc0c87a6ecc6afba6384ee5
  - url: 'https://github.com/advisories/GHSA-6vgg-xhvh-38ff'
tags:
  - ghsa
  - go
ingestedAt: '2026-07-07T15:41:59.219Z'
---

## Overview

`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.

## Affected
All released versions up to v0.3.0.

## Threat model
The 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.

## Suggested fix
Copy the four headers from the Web sibling:

```go
w.Header().Set("Content-Type", "application/yaml; charset=utf-8")
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
w.Header().Set("X-Content-Type-Options", "nosniff")
```

Mirrors `internal/web/handlers.go:1316-1321`. Add a parallel test to the existing web-side coverage.

## Suggested patch

Verified locally: `go vet`, `go test -race -count=1 ./...`, `golangci-lint v2.12` all clean.

```diff
diff --git a/internal/api/mobile_bundle.go b/internal/api/mobile_bundle.go
index fc09da0..73152eb 100644
--- a/internal/api/mobile_bundle.go
+++ b/internal/api/mobile_bundle.go
@@ -58,8 +58,15 @@ func (s *Server) handleMobileBundle(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	// Return YAML bundle with proper content-type
+	// Return YAML bundle with proper content-type. The bundle inlines a
+	// freshly-minted X25519 private key, so suppress every layer of cache
+	// between server and operator (intermediate proxies/CDNs, browser disk
+	// cache). Mirrors the Web-UI sibling at internal/web/handlers.go.
 	w.Header().Set("Content-Type", "application/yaml; charset=utf-8")
+	w.Header().Set("Cache-Control", "no-store")
+	w.Header().Set("Pragma", "no-cache")
+	w.Header().Set("Expires", "0")
+	w.Header().Set("X-Content-Type-Options", "nosniff")
 	w.WriteHeader(http.StatusOK)
 	if _, err := w.Write(bundle); err != nil {
 		s.logger.Error("write mobile bundle response", "error", err)
diff --git a/internal/api/mobile_bundle_test.go b/internal/api/mobile_bundle_test.go
index dcb8cd9..da08b01 100644
--- a/internal/api/mobile_bundle_test.go
+++ b/internal/api/mobile_bundle_test.go
@@ -52,6 +52,19 @@ func TestHandleMobileBundle_Success(t *testing.T) {
 		t.Errorf("Content-Type = %q, want 'application/yaml; charset=utf-8'", ct)
 	}
 
+	// Bundle inlines a private key — every cache between server and operator
+	// must drop the response. Mirrors the Web-UI sibling's headers.
+	for header, want := range map[string]string{
+		"Cache-Control":         "no-store",
+		"Pragma":                "no-cache",
+		"Expires":               "0",
+		"X-Content-Type-Options": "nosniff",
+	} {
+		if got := w.Header().Get(header); got != want {
+			t.Errorf("%s = %q, want %q", header, got, want)
+		}
+	}
+
 	// Verify body is valid YAML with expected keys
 	var yamlData map[string]interface{}
 	if err := yaml.Unmarshal(w.Body.Bytes(), &yamlData); err != nil {
```

## Affected packages

- `github.com/juev/nebula-mesh <= 0.3.1`

## Remediation

Upgrade to a patched release:

- `github.com/juev/nebula-mesh 0.3.2`
