Summary
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 24 hours.
Details
Enrollment tokens are bearer credentials for the public POST /api/v1/enroll endpoint: possession of a valid token allows enrolling the pending host and receiving a signed Nebula certificate/config for that host. The server configuration documents a security knob for their default lifetime and per-network overrides:
internal/config/server.go:82definesEnrollmentTokenTTLas the default lifetime for freshly minted enrollment tokens.internal/config/server.go:83documents per-network overrides innetwork_configunderenrollment_token_ttl.
The API server implements and consistently uses this resolver:
internal/api/server.go:77definestokenTTLFor, with precedence of per-networkenrollment_token_ttl, then server default, then 24h fallback.internal/api/server.go:82readsnetwork_config.enrollment_token_ttl.internal/api/server.go:89falls back to the configured server default.internal/api/hosts.go:190throughinternal/api/hosts.go:196usenow.Add(s.tokenTTLFor(r.Context(), host.NetworkID))for API host creation.
The Web UI sibling path does not call the resolver and instead always sets a 24-hour expiry:
internal/web/handlers.go:874mints the raw token forPOST /ui/hosts.internal/web/handlers.go:879setsExpiresAt: now.Add(24 * time.Hour).
This creates inconsistent behavior between API and Web UI host creation and bypasses an operator-configured token lifetime policy. The issue is reachable by an authenticated Web UI operator who can create hosts. Admins can create hosts in any network; non-admin operators can create hosts in networks whose CA they own.
Affected version evidence: the configurable enrollment-token TTL feature was introduced by commit 6c344a6 (feat(api): configurable enrollment-token TTL + regenerate endpoint (#75) (#79)), and git tag --contains 6c344a6 --sort=version:refname returns v0.3.0 through v0.3.8. Pattern checks across all release tags showed the TTL config/API resolver and the Web UI 24-hour hardcode are present in every v0.3.x release from v0.3.0 to v0.3.8, and are not meaningfully applicable to v0.1.x/v0.2.0 because the TTL policy knob was not present there. The current checkout at commit d92dd9a60de291e2bc1caf73b4e9a99567b31ec0 (git describe: v0.3.8-1-gd92dd9a) remains affected.
PoC
Safe local PoC run from a clean checkout at commit d92dd9a60de291e2bc1caf73b4e9a99567b31ec0 on 2026-06-12. The PoC is a temporary Go test that uses only in-memory SQLite and httptest; it does not start a real server and does not contact external services.
- Create a temporary test file
internal/web/security_audit_poc_test.goin packageweb. - In the test, create an in-memory Web UI with
newTestWeb(t), create a networkaudit-poc-netwith CIDR10.77.0.0/24, and setnetwork_config.enrollment_token_ttlto30m. - Log in as the seeded test admin through the normal Web UI helper and obtain a CSRF token from
GET /ui/hosts/new. - Submit
POST /ui/hostswithnetwork_id=audit-poc-net,name=audit-poc-host,nebula_ips=10.77.0.10,role=host, andkind=agent. - Parse the one-shot enrollment token from the returned host-detail page and read the token row with
GetEnrollmentToken. - Compare the observed expiry to the configured 30-minute network override.
Command run:
go test ./internal/web -run 'TestSecurityAuditPOC' -count=1 -v
Observed vulnerable output from this environment:
=== RUN TestSecurityAuditPOC_UIHostCreateIgnoresNetworkEnrollmentTokenTTL
POC_UI_TTL_BYPASS observed_token_ttl=24h0m0s configured_network_ttl=30m expires_at=2026-06-13T14:51:45Z
--- PASS: TestSecurityAuditPOC_UIHostCreateIgnoresNetworkEnrollmentTokenTTL (0.05s)
The meaningful control is the API sibling: internal/api/hosts.go:190 through internal/api/hosts.go:196 uses s.tokenTTLFor(...), and existing tests in internal/api/hosts_token_ttl_test.go verify API-created/regenerated enrollment tokens honor server-default and per-network TTLs. Variant review also found API regenerate-token, API re-enroll, and signed-poll rekey token minting use the resolver rather than a hardcoded 24h value. After recording the output, the temporary test file was removed and git status --short returned clean. The PoC was re-run after drafting this report and produced the output shown above.
Impact
An authenticated Web UI operator can bypass a configured enrollment-token lifetime policy and obtain a token valid for approximately 24 hours even when the deployment or network is configured for a much shorter lifetime such as 30 minutes. Because enrollment tokens are bearer credentials for the public enrollment endpoint, longer-than-intended validity increases the window in which a copied, logged, shared, or otherwise exposed token can be used to enroll the pending host and obtain its Nebula certificate/config. This weakens confidentiality and integrity for deployments relying on short token lifetimes to reduce enrollment-token exposure.
Suggested remediation: refactor the Web UI host-creation path to use the same TTL resolution as the API path, or move the resolver into a shared package/service used by both API and Web UI. Add a regression test under internal/web that sets network_config.enrollment_token_ttl = "30m", creates an agent host through POST /ui/hosts, and asserts the persisted enrollment token expires within the configured 30-minute window rather than 24 hours.
CVE-2026-55513 has a CVSS score of 5.4 (Medium). The vector is network-reachable, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (0.5.0); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-55513? CVE-2026-55513 is a medium-severity security vulnerability in github.com/forgekeep/nebula-mesh (go), affecting versions >= 0.3.0, < 0.5.0. It is fixed in 0.5.0.
- How severe is CVE-2026-55513? CVE-2026-55513 has a CVSS score of 5.4 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of github.com/forgekeep/nebula-mesh are affected by CVE-2026-55513? github.com/forgekeep/nebula-mesh (go) versions >= 0.3.0, < 0.5.0 is affected.
- Is there a fix for CVE-2026-55513? Yes. CVE-2026-55513 is fixed in 0.5.0. Upgrade to this version or later.
- Is CVE-2026-55513 exploitable, and should I be worried? Whether CVE-2026-55513 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-55513 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-55513? Upgrade
github.com/forgekeep/nebula-meshto 0.5.0 or later.