Apr 28, 2026·7 min read·7 visits
zrok versions prior to 2.0.1 fail to validate the targets of symbolic links in the WebDAV drive backend. This improper link resolution enables attackers to read or modify arbitrary files on the host filesystem, matching the privileges of the zrok process.
A critical vulnerability in the WebDAV drive backend of openziti/zrok allows unauthenticated or authenticated users to escape the designated shared directory. By creating or interacting with symbolic links, an attacker can achieve arbitrary file read and write access on the host system running the zrok process.
The zrok platform, built on OpenZiti, provides secure internet sharing capabilities, including a WebDAV drive backend designed to expose specific host directories to remote clients. This WebDAV component maps remote client requests to a designated physical directory on the host system, known as the DriveRoot. The security boundary relies on the assumption that users cannot interact with files outside this designated directory.
A critical flaw exists in how the WebDAV drive backend handles symbolic links (symlinks) within the DriveRoot. The application fails to restrict link resolution before performing standard filesystem operations. This vulnerability is classified as Improper Link Resolution Before File Access (CWE-59) and UNIX Symbolic Link Following (CWE-61).
Exploitation results in a complete bypass of the DriveRoot boundary. An attacker who accesses a maliciously crafted symlink via the WebDAV interface can interact with arbitrary files on the host operating system. The extent of the compromise depends entirely on the filesystem permissions granted to the process executing the zrok backend.
The root cause of this vulnerability lies in the path resolution logic within the zrok WebDAV drive backend. When handling HTTP requests for specific file resources, the application maps the requested URI to a physical path on the underlying operating system. In versions prior to 2.0.1, the backend constructs this physical path by appending the user-supplied path to the designated DriveRoot directory.
Crucially, the implementation fails to canonicalize the resulting path or verify the ultimate destination before executing filesystem operations. Standard Go operations such as Stat, OpenFile, and Mkdir execute directly against the concatenated path string. If the target file is a symbolic link, the Go runtime and underlying operating system natively and automatically follow it to its destination.
Because the backend lacks a strict directory jail or path-prefix validation post-resolution, it does not detect when a symbolic link redirects the file handle outside the intended DriveRoot. Consequently, the application processes the operation on the symlink's target, effectively bridging the security boundary between the restricted WebDAV share and the broader host filesystem.
Prior to the patch, the WebDAV backend performed direct mapping of requested paths without enforcing a canonicalized boundary check. The implementation relied on standard Go filesystem interfaces without implementing a custom wrapper to evaluate symlinks securely. This allowed standard filesystem routines to natively traverse symlinks pointing to absolute paths outside the share.
The fix introduced in version 2.0.1 (Commit 69b9b8d) fundamentally alters how paths are evaluated prior to I/O operations. The updated logic intercepts the requested path within functions handling Stat, OpenFile, and Mkdir operations. Instead of blindly executing the file operation, the application now programmatically determines the ultimate absolute path of the target.
To remediate the flaw, the developers introduced a canonicalization and path-prefix validation sequence. The code now evaluates the absolute path of the requested file, explicitly resolving all intermediate symbolic links. After determining the final physical path, the backend verifies that this resulting path is strictly a sub-path of the configured DriveRoot.
// Conceptual representation of the patched logic in zrok WebDAV backend
func (d *DriveBackend) secureOpen(requestedPath string) (File, error) {
// 1. Join requested path with DriveRoot
fullPath := filepath.Join(d.DriveRoot, requestedPath)
// 2. Canonicalize the path, resolving any symlinks (The Fix)
resolvedPath, err := filepath.EvalSymlinks(fullPath)
if err != nil {
return nil, err
}
// 3. Verify the canonical path remains within DriveRoot boundary
if !strings.HasPrefix(resolvedPath, d.DriveRoot) {
return nil, errors.New("path traversal detected")
}
// 4. Safe to open
return os.OpenFile(resolvedPath, os.O_RDWR, 0644)
}Exploiting this vulnerability requires specific preconditions. An attacker must possess write permissions to a zrok WebDAV share to create a malicious symlink. Alternatively, the attacker must manipulate an authorized user or internal process into placing a symlink within the shared directory, which the attacker can subsequently access via the WebDAV interface.
The exploitation phase begins with the creation of a symbolic link inside the DriveRoot. Using standard Unix utilities, the attacker links a benign-looking filename to a sensitive absolute path on the host system. For example, executing ln -s /etc/passwd payload.txt within the share establishes the traversal vector.
Once the symlink is in place, the attacker initiates a standard WebDAV GET request targeting the payload.txt file. The zrok backend receives the request, constructs the internal path, and calls the OpenFile equivalent. The OS transparently follows the symlink to /etc/passwd, and the backend returns the file contents in the HTTP response body.
If the WebDAV share is configured with write access, the exploitation scope expands significantly. The attacker can issue a WebDAV PUT request targeting a symlink that points to critical configuration files or executable paths. This primitive allows for arbitrary file overwriting, paving the way for persistent Remote Code Execution (RCE) via SSH key injection or cron job manipulation.
The security impact of GHSA-74M3-9QVM-RP9H is classified as High due to the resulting loss of filesystem confidentiality and integrity. The primary constraint on the attacker's capabilities is the privilege level of the operating system user running the zrok service. If the process runs as an unprivileged user, the attacker is limited to files accessible by that specific account.
The confidentiality impact is absolute within the context of the service user. Attackers can extract sensitive system files, environment variables, application source code, and configuration files. Exposure of items such as SSH private keys, database connection strings, or OpenZiti identity materials can facilitate lateral movement and further compromise of the infrastructure.
The integrity impact is equally severe if the WebDAV share permits write operations. Attackers can leverage the symlink traversal primitive to overwrite host files. Modifying files such as ~/.ssh/authorized_keys or /etc/shadow enables privilege escalation or remote code execution, transforming a localized directory traversal into a complete host takeover.
The definitive remediation for this vulnerability is upgrading the github.com/openziti/zrok package to version 2.0.1 or later. The patched version incorporates the necessary path canonicalization and directory boundary checks to strictly isolate the WebDAV backend to the configured DriveRoot.
In environments where immediate patching is not operationally feasible, administrators must apply compensating controls. If the WebDAV sharing functionality is not actively required, disabling the WebDAV drive backend completely eliminates the attack surface. Alternatively, administrators can mount the WebDAV share with strictly read-only permissions to prevent the upload or creation of malicious symlinks by unauthorized actors.
Operating system-level mitigations should also be enforced. Following the principle of least privilege, the zrok service must execute under a dedicated, tightly restricted service account. Running zrok as root or an administrative user exponentially increases the severity of a directory escape. Furthermore, deploying zrok within a dedicated container or chroot jail provides a defense-in-depth layer that restricts filesystem access even if the application-level boundary fails.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
openziti/zrok OpenZiti | < 2.0.1 | 2.0.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-59, CWE-61 |
| Attack Vector | Network |
| CVSS v3.1 Score | 8.8 (High) |
| Exploit Status | Proof of Concept |
| Confidentiality Impact | High |
| Integrity Impact | High |
Improper Link Resolution Before File Access ('Link Following')