Headplane: Path Traversal & RBAC Bypass
Path traversal and RBAC bypass in Headplane: any authenticated OIDC user can rename and expire other nodes and users.
Advisory ID: TP-2026-003
Product: Headplane (web UI for Headscale)
Vulnerability type: Path traversal (CWE-22) + improper authorization / RBAC bypass (CWE-863)
CVE: CVE-2026-46484
CVSS 3.1: 8.1 (High) · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
Affected versions: stable ≤ 0.6.2, beta 0.7.0-beta.1 and 0.7.0-beta.2
Patched in: 0.6.3, 0.7.0-beta.3
Vendor advisory: GHSA-vgj6-hcf2-fqf6
Reported: 26 April 2026
Summary
Headplane is a widely used web interface for managing Headscale, the self-hosted control server for Tailscale networks. The renameNode function interpolates the user-supplied name into the Headscale request path without URL-encoding. Node.js normalizes the path-traversal segments before sending, redirecting the request to a foreign endpoint, while the authorization check validates only the attacker's own node carried in the request. As a result, any authenticated OIDC user, regardless of role, can rename and expire arbitrary nodes and user accounts.
Root cause
The renameNode action builds the Headscale path v1/node/${nodeId}/rename/${newName} and does not apply encodeURIComponent to newName (app/server/headscale/api/endpoints/nodes.ts:149). The request is sent via new URL(url, baseUrl), which normalizes ../ segments, so v1/node/1/rename/../../2/expire becomes v1/node/2/expire (app/server/headscale/api/index.ts:126). The authorization check validates the node from the form field node_id, the attacker's own node, not the traversal target (app/routes/machines/machine-actions.ts:64). The same unguarded pattern exists in renameUser (app/server/headscale/api/endpoints/users.ts:84), there behind the write_users capability. encodeURIComponent() is applied to neither path segment.
Proof of Concept
A valid, low-privileged OIDC session is enough. The rename value carries a traversal sequence to another node's expire endpoint:
POST /admin/machines HTTP/1.1
Cookie: _hp_auth=<session of a low-privileged OIDC user>
Content-Type: application/x-www-form-urlencoded
action_id=rename&node_id=<own_node_id>&name=../../<foreign_node_id>/expire
Headplane normalizes the path via new URL() and forwards POST /api/v1/node/<foreign_node_id>/expire to Headscale, which executes it. Live-tested with caps=0, caps=1, and caps=1323: all expire a node the attacker does not own.
Impact
- Expire arbitrary nodes, including admin nodes, cutting their connectivity.
- Rename arbitrary nodes, breaking MagicDNS names.
- Rename Headscale users via the
write_userspath. - Exploitable by any authenticated OIDC user with no capability bits.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.
