Mar 10, 2026·6 min read·5 visits
Actual Sync Server < 26.3.0 is vulnerable to an authenticated path traversal (CWE-22) via the `x-actual-file-id` header, allowing arbitrary file read/write and potential code execution. Update to version 26.3.0.
CVE-2026-3089 is an authenticated path traversal vulnerability in Actual Sync Server prior to version 26.3.0. By manipulating the `x-actual-file-id` HTTP header, an authenticated attacker can bypass directory restrictions to read or write arbitrary files on the host filesystem. This flaw stems from a lack of input validation when constructing file paths for user uploads and downloads.
Actual Sync Server acts as the backend component for the Actual Budget application, handling synchronization, file storage, and user data management. The server exposes specific HTTP endpoints, /sync/upload-user-file and /sync/download-user-file, to manage budget data files associated with authenticated user sessions. These endpoints rely on client-provided metadata to determine the storage location on the local filesystem.
CVE-2026-3089 identifies a path traversal vulnerability (CWE-22) within these file synchronization endpoints. The server fails to sanitize the x-actual-file-id HTTP header before appending it to a base directory path. This architectural oversight allows an authenticated user to supply directory traversal sequences to escape the intended sandbox directory.
The consequence of this vulnerability is arbitrary file read and write access on the underlying host operating system. The process permissions dictate the exact scope of accessible files, but it typically includes application configuration files, user databases, and execution scripts. If the attacker overwrites executable files or configuration scripts, this access can escalate to remote code execution.
The root cause of CVE-2026-3089 is the direct incorporation of unvalidated user input into filesystem operations. When a client initiates a file synchronization request, the server extracts the file identifier directly from the x-actual-file-id HTTP header. The application implicitly trusts this value to be a safe, well-formed identifier such as a UUID.
Once extracted, the fileId variable is passed to the FilesService component, which manages local storage operations. The service constructs the final absolute path by concatenating a base directory, such as userFiles/, with the provided fileId. Because the application employs standard path resolution libraries without prior sanitization, any relative traversal segments included in the fileId are processed by the underlying operating system.
This behavior enables the path resolution to traverse upward from the base directory. For example, supplying a value of ../../../../etc/passwd combined with a base path of /app/data/userFiles/ results in a normalized path of /etc/passwd. The application subsequently performs read or write operations on this normalized path, completely bypassing the intended directory restrictions.
The vulnerable implementation retrieves the fileId directly from the request headers without invoking any validation routines. The extracted value is immediately utilized in a path join operation. The lack of a validation layer means any string sequence accepted by the HTTP parser is forwarded to the filesystem API.
The following code snippet illustrates the vulnerable extraction pattern prior to version 26.3.0:
// Vulnerable implementation
let fileId = req.headers['x-actual-file-id'];
// fileId is passed directly to the filesystem moduleThe patch introduced in commit 18072e1d8b5281db43ded8b21433ee177bae9dfa mitigates this vulnerability by implementing a strict allowlist approach. A regular expression, ^[A-Za-z0-9_-]+$, is defined to restrict the permitted characters within the fileId. The development team introduced a type-guard function, isValidFileId, to enforce this constraint before any path construction occurs.
The updated code validates the header immediately upon extraction. If the input contains unauthorized characters, such as periods or slashes, the server terminates the request with a 400 Bad Request status.
// Patched implementation
const FILE_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
function isValidFileId(fileId: unknown): fileId is string {
return typeof fileId === 'string' && FILE_ID_PATTERN.test(fileId);
}
let fileId = req.headers['x-actual-file-id'];
if (!isValidFileId(fileId)) {
res.status(400).send('invalid fileId');
return;
}Exploitation of CVE-2026-3089 requires an attacker to possess valid authentication credentials for the Actual Sync Server. The attacker must first authenticate to obtain a legitimate session token, which is submitted via the x-actual-token header. This prerequisite limits the attack surface to registered users or attackers who have previously compromised an account.
With a valid token, the attacker constructs a malicious HTTP POST request directed at the /sync/upload-user-file endpoint. The critical component of this request is the injection of the x-actual-file-id header with a path traversal payload. The payload specifies the relative path to the target file the attacker intends to overwrite, such as ../../package.json.
The payload body contains the data to be written to the target location. The server processes the request, resolves the traversal path, and writes the provided data to the specified file. The following curl command demonstrates a proof-of-concept for an arbitrary file write:
curl -X POST "https://sync-server.example.com/sync/upload-user-file" \
-H "x-actual-token: [VALID_AUTH_TOKEN]" \
-H "x-actual-file-id: ../../package.json" \
-H "Content-Type: application/encrypted-file" \
--data-binary "@malicious_package.json"A similar methodology applies to the /sync/download-user-file endpoint. By substituting the POST request with a GET request and targeting a sensitive file via the traversal header, the attacker forces the server to return the contents of the specified file. This facilitates the extraction of configuration files, environment variables, or other sensitive data stored on the filesystem.
The primary impact of CVE-2026-3089 is the complete loss of filesystem confidentiality and integrity within the execution context of the Actual Sync Server process. An authenticated attacker can read any file that the service account has permissions to access. This exposure includes application source code, database files, cryptographic keys, and environment variables.
The ability to write arbitrary files introduces a high risk of remote code execution. An attacker can overwrite executable scripts, such as database migration files or application initialization routines. Upon the next server restart or routine execution, the compromised scripts will execute with the privileges of the server process.
The CVSS v4.0 score of 5.3 reflects the authenticated nature of the vulnerability and the specific metrics evaluated. However, in environments where the synchronization server runs with elevated privileges or lacks strict filesystem isolation, the operational impact can be severe. The vulnerability facilitates lateral movement and complete host compromise if the server is not properly containerized.
The following diagram illustrates the exploitation flow for the arbitrary file write vector.
The definitive remediation for CVE-2026-3089 is upgrading the Actual Sync Server to version 26.3.0 or later. This release incorporates the strict regular expression validation for the x-actual-file-id header, effectively neutralizing the path traversal vector. Administrators should prioritize patching systems exposed to untrusted users or external networks.
In scenarios where immediate patching is not feasible, organizations must deploy compensating controls. Implementing a Web Application Firewall (WAF) rule to inspect the x-actual-file-id HTTP header can block malicious requests. The WAF rule should drop any request where this header contains period (.), slash(/), or backslash (\) characters.
Defense-in-depth measures should be applied to restrict the capabilities of the server process. The application should be executed within a containerized environment with minimal filesystem access. Employing read-only volume mounts for application code and restricting write permissions strictly to the userFiles directory mitigates the impact of arbitrary file write vulnerabilities.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Actual Sync Server Actual Budget | < 26.3.0 | 26.3.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network |
| CVSS Score | 5.3 (v4.0) |
| Impact | Arbitrary File Read/Write, Potential RCE |
| Exploit Status | Proof-of-Concept Available |
| Authentication | Required (Valid Token) |
| Patched Version | 26.3.0 |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.