nebula-mesh: API endpoints lack ownership checks, enabling cross-operator privilege escalation
Date: 2026-06
Affected: go/github.com/juev/nebula-mesh
Attack vector: auth-bypass
Category: vulnerability-disclosure
Severity: Critical
CVE: CVE-2026-47724
CWE: CWE-862
CVSS: 9.9 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)

The `/api/v1/*` route surface trusts the bearer token alone for authorisation on most endpoints. The codebase itself admits this at `internal/api/hosts.go:384`: *"API trusts the bearer token for authorisation; per-CA ownership is enforced only in the Web layer."* The Web UI gates state-changing routes through `loadAccessibleCA` (`internal/web/cas.go`); CA-management endpoints in `internal/api/cas.go` ALSO have proper `canAccessCA` gates. **The gap is on the host, network, firewall, mobile-bundle, and most operator endpoints.** Combined with the per-operator CA model from ADR 0002, this gives any non-admin operator API key broad cross-tenant access — instant privilege escalation in the worst case. ## Affected All released versions prior to v0.3.4. ## Exploit chain ### A) Mint admin API key from any operator key (instant privilege escalation) `internal/api/operators.go:118` — `handleCreateOperatorAPIKey` does no admin check and no actor/target-operator ownership check. Any operator key can call it for any operator (including admins) and receive a fresh bearer. ``` curl -X POST -H "Authorization: Bearer <low-priv-key>" \ https://server/api/v1/operators/<admin-id>/api-keys \ -H 'Content-Type: application/json' -d '{"name":"oops"}' # Returns: {"key":"<32-byte admin bearer>","entry":{...}} ``` Reuse the returned key for subsequent requests → full admin. ### B) Cross-operator host takeover via reenroll `internal/api/hosts.go:321,330` → `mintEnrollmentTokenForHost`. Looks


Mitigations:

Architectural layers (MAESTRO):