Sep 19, 2026·6 min read·20 visits
Unvalidated project query parameters in Perses allow authenticated path traversal and arbitrary JSON/YAML file reading when using the file-system database.
An arbitrary file read and path traversal vulnerability exists in Perses prior to version 0.54.0-rc.0. When configured with a file-system database backend, the application lacks input validation on the request-controlled project query parameter. An authenticated attacker with low privileges can supply directory traversal sequences to read arbitrary JSON or YAML files on the host file system.
Perses is an open-source observability dashboard and visualization platform designed to display operational metrics and logs. To manage dashboard assets, credentials, and custom configurations, Perses organizes resources into distinct project boundaries. When deployed with a local file-system database backend, these assets are stored directly on the host disk as JSON or YAML files.
The attack surface exists in the application's list endpoints, such as the dashboards and datasources query APIs. These endpoints expose query parameters that allow users to restrict operations to specific projects. However, the system does not sufficiently sanitize or validate these input parameters against path-traversal sequences before passing them to the file-resolution engine.
An authenticated attacker with low privileges can exploit this flaw by submitting crafted HTTP requests. By injecting path traversal sequences into the project parameter, the attacker can break out of the designated project directory. Consequently, the application will retrieve and display arbitrary configuration files stored on the filesystem.
The vulnerability stems from an improper implementation of pathname limitations, classified under CWE-22. Perses supports multiple database backends, including an option to store configurations on a local directory hierarchy. When processing list requests, the application extracts the value of the project query parameter to locate the targeted directory on disk.
Before the implementation of the patch, the value of projectQueryParameter was mapped directly into the database query structure. The application failed to perform any input validation, such as checking for directory traversal symbols like dot-dot-slash. Because the backend constructs absolute paths using simple string formatting or unsanitized path joining, these traversal sequences remained intact during system resolution.
During file-system operations, the operating system evaluates the traversal sequences and resolves the path relative to parent directories. This behavior allows the query to escape the intended sandbox directory, which is normally isolated to /var/lib/perses/database/projects/{project}. As a result, the application opens and parses any JSON or YAML formatted files within the privileges of the running daemon.
An examination of the vulnerable code in the internal/api/toolbox/list.go file shows that the application accepted the project parameter without verification. The extracted value was processed and forwarded directly to the backend database layers. The absence of a sanitization step meant that the backend completed file system queries on any arbitrary resolved path.
// Vulnerable Implementation (Before Patch)
func (t *toolbox[T, K, V]) list(ctx echo.Context, parameters apiInterface.Parameters, query V) (any, error) {
projectQueryParameter := query.GetProjectQueryParam()
if len(projectQueryParameter) > 0 {
if len(parameters.Project) > 0 && parameters.Project != projectQueryParameter {
return nil, apiInterface.HandleBadRequestError(fmt.Sprintf("the project name in the path (%s) and the project name in the query parameter (%s) are different", parameters.Project, projectQueryParameter))
}
}
// ... subsequent direct database query execution using projectQueryParameter ...
}The security patch remediates the flaw by introducing strict identifier validation prior to processing. The code now imports the github.com/perses/spec/go/common package and invokes the common.ValidateID() function. This validation logic verifies that the input complies with standard identifier formats, rejecting special characters such as forward slashes, backslashes, and dot segments.
// Patched Implementation
import (
// ... other imports ...
"github.com/perses/spec/go/common"
)
func (t *toolbox[T, K, V]) list(ctx echo.Context, parameters apiInterface.Parameters, query V) (any, error) {
projectQueryParameter := query.GetProjectQueryParam()
if len(projectQueryParameter) > 0 {
// Added validation to block traversal patterns
if err := common.ValidateID(projectQueryParameter); err != nil {
return nil, apiInterface.HandleBadRequestError(fmt.Sprintf("the project name in the query parameter is invalid: %s", err.Error()))
}
if len(parameters.Project) > 0 && parameters.Project != projectQueryParameter {
return nil, apiInterface.HandleBadRequestError(fmt.Sprintf("the project name in the path (%s) and the project name in the query parameter (%s) are different", parameters.Project, projectQueryParameter))
}
}
// ... subsequent safe query execution ...
}To execute this exploit, an attacker must first obtain valid credentials to the target Perses instance. Even low-privileged account credentials are sufficient since the vulnerable list API endpoints do not require administrative privileges. Once authenticated, the attacker can leverage standard API utilities or web browsers to send crafted HTTP queries.
The attacker constructs an HTTP GET request to endpoints like /api/v1/dashboards or /api/v1/datasources. By appending a modified project query parameter containing traversal sequences, the attacker instructs the backend to look outside its normal sandbox. For example, a parameter such as ?project=../../another-project directs the file resolution engine to load configuration details from a separate, isolated tenant.
Because the backend expects files to conform to YAML or JSON schemas, arbitrary binary or plain text files may cause the parser to fail. However, any structural application metadata, credential stores, or other project configurations stored in these formats are parsed successfully. The resulting server response exposes the contents of the target files to the attacker, leading to unauthorized information disclosure.
The impact of this vulnerability is assessed as High, with a CVSS v4.0 base score of 7.1. The primary security consequence is the loss of confidentiality across project boundaries. In multi-tenant environments where projects are intended to remain isolated, an attacker can enumerate and read configurations belonging to other users.
Furthermore, dashboards and datasources often contain sensitive configuration parameters. These files may store plaintext database credentials, API tokens, connection strings, or system metadata. Access to these parameters allows an attacker to compromise downstream systems, pivoting deeper into the organization's infrastructure.
Because the vulnerability is limited to file-system-based databases, environments running external databases such as Etcd are unaffected. However, for vulnerable deployments, the exploitation process leaves standard HTTP logs, which might not immediately indicate the malicious nature of the path traversal. This stealth increases the likelihood of prolonged exposure before detection.
The primary remediation path is to upgrade the Perses installation to version 0.54.0-rc.0 or higher. This update integrates the identifier validation logic across all affected list API endpoints. By implementing this validation, the application successfully blocks requests containing path traversal sequences at the input validation stage.
If upgrading immediately is not viable, administrators should deploy defense-in-depth measures. A Web Application Firewall (WAF) or reverse proxy can be configured with rules to inspect query parameters. Rules should block incoming HTTP requests containing sequences like ../, ..%2f, or ..\ in the project query parameter.
Additionally, applying the principle of least privilege to the Perses operating system user reduces the attack surface. Ensure the Perses service runs under a dedicated, non-privileged user account. Restricting host-level directory access prevents the service from reading sensitive configurations even if the application layer is compromised.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Perses Perses | < 0.54.0-rc.0 | 0.54.0-rc.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network |
| CVSS v4.0 Score | 7.1 |
| Privileges Required | Low |
| Exploit Status | None |
| CISA KEV Status | Not Listed |
The product uses external input to construct a pathname that is intended to identify a file or directory that is located beneath a restricted parent directory, but the product 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.
CVE-2026-62374 (GHSA-f9j6-8p6x-r9j6) is a verification bypass vulnerability in the OpenWallet Foundation SD JWT JS library (@sd-jwt/core and @sd-jwt/decode versions 0.19.0 and earlier). Due to permissive UTF-8 decoding and the omission of mandatory reference checks during presentation verification, tampered or unreferenced disclosures are silently dropped rather than rejected. This deviates from RFC 9901 §7.1 requirements and allows attackers to execute silent claim-set reduction attacks against relying parties.
An interpretation conflict in Bytebase DBHub (< 0.22.6) allows attackers to bypass read-only SQL query restrictions when connected to MySQL or MariaDB instances. Because DBHub's custom SQL tokenizer treats any '--' sequence as a comment, whereas MySQL and MariaDB require trailing whitespace or a control character, crafted queries containing '--' immediately followed by non-whitespace characters allow stacked destructive SQL statements to execute on connections configured as read-only.
CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.
CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.
CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).
CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.