Skip to main content

nebula-mesh CVE-2026-47722

HIGH
Code Injection (CWE-94)
2026-06-08 https://github.com/juev/nebula-mesh GHSA-7hp6-g3pq-3pc3
Share

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 08, 2026 - 23:34 vuln.today
Analysis Generated
Jun 08, 2026 - 23:34 vuln.today

DescriptionCVE.org

internal/configgen/generator.go:86,108,119 interpolates the operator-supplied ListenHost and TunDevice fields raw into a text/template that produces the agent's config.yml. internal/web/advanced.go:20-35 accepts both with only strings.TrimSpace - no character or shape validation.

Exploit

An operator (or attacker with any operator key, given the cross-tenant CRUD advisory) sets adv_tun_device to:

nebula0
lighthouse:
  am_lighthouse: true
  hosts: ["10.0.0.1"]
#

The agent fetches the rendered config on its next signed poll. On config reload, it loads the injected YAML keys: the host self-promotes to lighthouse, attracts mesh traffic, or sets am_relay: true to be selected as a relay. The ListenHost field has the same shape.

Affected

All released versions prior to v0.3.2.

Threat model

  • Today: operator can compromise their own host's config (trivially allowed if they own the host, but they can also set lighthouse/relay flags that the operator-create form does NOT expose - privilege uplift within their own tenant).
  • Combined with the critical /api/v1 authz advisory: any operator key can mutate ANOTHER tenant's host overrides and inject YAML there.
  • Post-fix of the authz advisory: still relevant - the agent unconditionally trusts whatever config the server hands it, so any future operator-impersonation bug re-amplifies this.

Suggested fix

Two options, either acceptable:

  1. Input validation in parseAdvancedFromForm (internal/web/advanced.go):
  • ListenHost: regex ^[A-Za-z0-9.:\[\]_-]+$ (IPv4/IPv6/hostname)
  • TunDevice: regex ^[A-Za-z0-9_-]{1,15}$ (Linux IFNAMSIZ caps at 15)

Reject invalid input with a form-level error; do not write to the host row.

  1. Safer marshalling: switch configgen/generator.go to marshal a typed Go struct via gopkg.in/yaml.v3 (which escapes correctly) instead of text/template string-concat. Larger change, but eliminates this entire injection class.

Option 2 is preferable long-term. Option 1 is the quick fix.

The unsafe_routes advanced field is already netip.Parse{Prefix,Addr}-validated at enroll.go:226-233 - apply the same validation discipline to the other advanced fields.

AnalysisAI

YAML injection in nebula-mesh (juev/nebula-mesh, forked as forgekeep/nebula-mesh) prior to v0.3.2 allows an authenticated operator to inject arbitrary YAML keys into a managed agent's config.yml via the unvalidated adv_tun_device and ListenHost host-override fields. A successful injection lets the attacker self-promote a target host to a Nebula lighthouse or relay, redirecting and intercepting mesh traffic across the overlay network. No public exploit identified at time of analysis, but a detailed PoC payload is published in the GHSA advisory itself.

Technical ContextAI

nebula-mesh is a Go web UI that manages Slack's Nebula overlay-network agents. The vulnerable code path is in internal/configgen/generator.go (lines 86, 108, 119), where operator-supplied strings are interpolated raw into a text/template that renders the agent's YAML config.yml. The form handler in internal/web/advanced.go (lines 20-35) only calls strings.TrimSpace on the inputs, performing no character-class or shape validation. This is a textbook CWE-94 (Improper Control of Generation of Code) realized as YAML injection: because text/template performs string concatenation rather than YAML-aware escaping, newlines and structural characters in the input become live YAML syntax. Notably, the adjacent unsafe_routes field is already netip.Parse{Prefix,Addr}-validated at enroll.go:226-233, so the defect is an inconsistency in validation discipline across advanced fields.

RemediationAI

Vendor-released patch: 0.3.2 - upgrade github.com/juev/nebula-mesh (or the forgekeep/nebula-mesh fork) to v0.3.2 or later; the fix commit is https://github.com/forgekeep/nebula-mesh/commit/c1506f7344ab375a145a7449b193af3f19bb41ef, which replaces the text/template renderer with gopkg.in/yaml.v3 typed-struct marshaling so structural-break characters are quoted as scalars rather than concatenated into YAML structure. If immediate upgrade is not possible, the advisory recommends enforcing input validation in parseAdvancedFromForm (internal/web/advanced.go) - regex ^[A-Za-z0-9.:\[\]_-]+$ for ListenHost and ^[A-Za-z0-9_-]{1,15}$ for TunDevice (the latter matching Linux IFNAMSIZ) - and rejecting form submissions that fail; the trade-off is that this only closes the known fields and leaves the underlying string-concat renderer vulnerable to any future advanced field added without similar validation. As a defensive control, restrict operator-UI access to a trusted management network and consider patching the related /api/v1 authorization advisory in tandem, since unfixed cross-tenant CRUD turns this single-tenant flaw into a cross-tenant compromise. Full advisory: https://github.com/juev/nebula-mesh/security/advisories/GHSA-7hp6-g3pq-3pc3.

Share

CVE-2026-47722 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy