Advisories for Golang/Github.com/Forgekeep/Nebula-Mesh package

2026

nebula-mesh: Web UI host creation ignores configured enrollment token TTL and mints 24-hour bearer enrollment tokens

The nebula-mgmt Web UI host-creation path ignores both the server-wide enrollment_token_ttl security setting and per-network network_config.enrollment_token_ttl overrides. API host creation and token-regeneration paths use the configured TTL resolver, but POST /ui/hosts hardcodes now.Add(24 * time.Hour) for newly minted agent enrollment tokens. In deployments that intentionally reduce enrollment-token lifetime, any authenticated operator who can create a host through the Web UI can still mint a bearer enrollment token valid for about …

nebula-mesh: Unauthenticated OIDC login endpoint allocates unbounded in-memory state entries without rate limiting

When OIDC is enabled, GET /ui/oidc/login is reachable without authentication and is registered outside the Web UI rate-limited auth routes. Every request creates a fresh random OIDC state value and stores it in an in-memory map for 10m. Expired states are swept lazily, but there is no rate limit or maximum live-state cap on the allocation path. An unauthenticated remote client can therefore grow OIDC.states for the full state TTL, …

nebula-mesh: Operator session tokens stored in plaintext in the database

Operator session tokens are stored in plaintext in the operator_sessions table (the token column is the PRIMARY KEY). The session token is a 32-byte random hex value sent directly in a cookie and valid for 24 hours. internal/models/operator.go:61 — OperatorSession.Token holds the plaintext token. internal/store/sqlite_operators.go:590 — CreateOperatorSession inserts sess.Token verbatim. internal/store/sqlite_operators.go:603,642,681,698 — lookups/updates/deletes use WHERE token = ? against the plaintext value. Anyone who can read the database (backup, snapshot, …

nebula-mesh: Certificate revocation is never enforced at the mesh

nebula-mesh revokes a host by adding its certificate fingerprint to a per-CA blocklist and shipping that list to every other agent on each poll. Slack's Nebula enforces certificate revocation ONLY through the pki.blocklist list in config.yml (no CRL/OCSP). The project's own code states this: internal/pki/durations.go:15 — "Revocation via the blocklist remains the immediate security control." The server side is fully implemented (computes per-CA blocklist via GetBlocklistForCA, returns it in the …

nebula-mesh: CA private key not zeroized on web mobile-bundle error paths

The web handler renderMobileBundle (internal/web/handlers.go:1325) passes the real *pki.CAResolver directly into mobilebundle.Build. Inside Build (internal/mobilebundle/builder.go:54), resolver.LoadByID decrypts the CA's ed25519 private key into a *pki.CAManager, but Build never calls CAManager.Wipe() on any return path (success or any of the error paths at lines 56, 62, 68, 80, 86, 92, 98, 102, 109, 118, 150). As a result, when a mobile-bundle request goes through the web UI and Build returns — …

Nebula-mesh allows non-admin operators to disable webhook SSRF protection via `allow_private`

Non-admin operators (role user) can set allow_private: true on their own managed webhook subscription (POST/PATCH /api/v1/webhook-subscriptions). No admin check exists on this field. At delivery time, allow_private switches the dispatcher to an unguarded HTTP client, bypassing the private/loopback/link-local SSRF guard — letting a low-privilege operator make the server request internal addresses.

nebula-mesh: Decrypted CA private key persists in heap after signing

internal/pki/resolver.go:36-64 constructs a CAManager with the plaintext ed25519.PrivateKey after unwrapping via the master key; internal/pki/ca.go:13-16 stores it. Callers at internal/api/enroll.go:116, internal/api/updates.go:297, and internal/api/mobile_bundle.go:40 use the manager for one Sign() and drop the reference on function return — but the underlying slice contents are not wiped before release. The keystore package's contract (internal/keystore/keystore.go doc: "Callers MUST zeroise the returned plaintext DEK as soon as it is no longer needed") is not …