Apr 10, 2026·5 min read·3 visits
An IDOR flaw in Beszel Hub allows authenticated users to access other users' systems by providing a 15-character system ID. The patch in version 0.18.7 introduces explicit ownership validation.
CVE-2026-40077 is an Insecure Direct Object Reference (IDOR) vulnerability in the Beszel Hub API prior to version 0.18.7. The flaw allows authenticated users to bypass authorization controls and access sensitive container logs, retrieve systemd metadata, or trigger SMART disk scans on monitoring agents belonging to other users.
Beszel is a server monitoring platform built around a central Hub and distributed agents. The Hub component utilizes the PocketBase framework to manage relationships, users, and monitoring targets. PocketBase inherently provides Relationship-Based Access Control (RBAC) on standard collection operations. The Beszel Hub implements several custom API routes to proxy requests directly to remote monitoring agents.
Prior to version 0.18.7, the Beszel Hub failed to enforce proper authorization constraints on these custom API routes. An Insecure Direct Object Reference (IDOR) vulnerability existed within the handlers responsible for interacting with the monitoring agents. The flaw allowed any authenticated user to interact with systems associated with other users.
The vulnerability relies on the attacker knowing or obtaining a target system's 15-character alphanumeric ID. By supplying this ID to specific endpoints, an attacker can bypass the intended access controls. The affected endpoints primarily handle fetching container logs, retrieving systemd metadata, and initiating SMART hardware data refreshes.
The root cause of CVE-2026-40077 is a Broken Access Control implementation within the custom API handlers in internal/hub/api.go. The handlers correctly extracted the system query parameter but failed to cryptographically or logically verify that the authenticated user owned the specified system.
When processing a request, the vulnerable code invoked h.sm.GetSystem(systemID) to retrieve the system record. The method only verified that the 15-character system ID existed within the database. It did not intersect the system record with the users relation field associated with the requester's JSON Web Token (JWT) identity.
Because the PocketBase RBAC rules only apply to the framework's auto-generated CRUD endpoints, the custom proxy routes required explicit, manual authorization checks. The omission of this manual check meant that the application blindly trusted the user-supplied system ID, proxying the request to the target agent regardless of the user's actual permissions.
The vulnerability resided in the custom request handlers that bridged the PocketBase HTTP layer and the remote agents. The vulnerable implementation directly utilized the systemID provided in the HTTP GET query parameters.
func (h *Hub) containerRequestHandler(e *core.RequestEvent) error {
systemID := e.Request.URL.Query().Get("system")
// Vulnerable: Retrieves system without verifying membership
system, err := h.sm.GetSystem(systemID)
if err != nil {
return e.JSON(http.StatusNotFound, "System not found")
}
// Proceed to contact agent...
}The remediation introduced in commit ba10da1b9f13455f2879336445102a45eb6cb07b implemented a strict authorization gate. The developers added a HasUser method that validates the requester's ID (e.Auth.Id) against the users slice embedded within the system record.
func (h *Hub) containerRequestHandler(e *core.RequestEvent, fetchFunc func(*system.System, string) (string, error), responseKey string) error {
systemID := e.Request.URL.Query().Get("system")
containerID := e.Request.URL.Query().Get("container")
system, err := h.sm.GetSystem(systemID)
// Patched: Mandatory membership validation using HasUser()
if err != nil || !system.HasUser(e.App, e.Auth.Id) {
return e.NotFoundError("", nil)
}
// ...
}To prevent ID enumeration, the patched implementation returns a generic 404 Not Found error for both non-existent systems and unauthorized access attempts. This design choice obscures the validity of guessed system IDs from potential attackers.
Exploitation of CVE-2026-40077 requires an attacker to possess a valid authentication token and the target system's 15-character alphanumeric ID. The attacker first registers or compromises a low-privileged user account on the target Beszel Hub to obtain a valid JWT.
The attacker must then acquire the target systemID. While these IDs are randomly generated strings, they are occasionally leaked through secondary Hub API endpoints or misconfigurations. Once the ID is obtained, the attacker crafts direct HTTP requests to the vulnerable custom endpoints.
An example exploit request targeting Docker container logs involves appending the target system ID and container ID to the endpoint URI. The attacker issues a GET request to /api/beszel/containers/logs?system=[TARGET_ID]&container=[CONTAINER_ID]. The Hub processes the request, bypasses authorization, and returns the raw log output from the remote agent.
The primary impact of this vulnerability is partial information disclosure. An attacker can read real-time logs from any Docker container running on a targeted, unauthorized system. Container logs frequently contain sensitive operational data, including application secrets, Personally Identifiable Information (PII), API keys, and environment variables.
Beyond information disclosure, the vulnerability enables unauthorized administrative actions on the remote agents. Attackers can force the agents to initiate SMART disk scans by POSTing to /api/beszel/smart/refresh?system=[TARGET_ID]. Repeatedly triggering these hardware operations can lead to localized resource exhaustion and premature wear on storage mediums.
Attackers can also retrieve systemd unit properties via the /api/beszel/systemd/logs equivalent endpoints. This capability allows malicious actors to map the internal architecture and service dependencies of the target host, facilitating further lateral movement or targeted exploitation. The overall severity is moderated by the requirement for authentication and prior knowledge of the 15-character system ID.
The vulnerability is fully addressed in Beszel version 0.18.7. Organizations deploying Beszel Hub must upgrade to this release or later to ensure the custom API proxy routes correctly enforce user ownership validation. The patch relies on the HasUser mechanism to permanently close the IDOR vector.
In addition to the core authorization patch, the developers introduced secondary hardening measures in commit 5463a38f0f426b45272dff7bffcd351fe5ddcf03. The implementation now includes requireAdminRole and excludeReadOnlyRole middleware functions. These middlewares prevent low-privileged accounts (such as 'readonly' users) from accessing sensitive administrative tokens or triggering SMART refreshes, effectively enforcing the principle of least privilege.
If immediate patching is not possible, administrators should review user roles within the Hub. Organizations should ensure that guest or untrusted accounts are restricted to 'readonly' permissions or removed entirely. Additionally, operators should audit access logs for unusual HTTP 404 errors or high-frequency requests to /api/beszel/containers/logs, which indicate active system ID enumeration attempts.
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Beszel henrygd | < 0.18.7 | 0.18.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-184, CWE-639 |
| Attack Vector | Network |
| CVSS Base Score | 3.5 |
| EPSS Percentile | 14.91% |
| Impact | Information Disclosure |
| Exploit Status | Proof-of-Concept |
| KEV Listed | False |
Insecure Direct Object Reference (IDOR)