Oct 10, 2026·4 min read·1 visit
Unsanitized query parameters in Shiny for Python's session bookmark feature allow unauthenticated path traversal and arbitrary file read.
A path traversal vulnerability in Shiny for Python (posit-dev/py-shiny) versions 1.4.0 through 1.6.3 allows unauthenticated remote attackers to read arbitrary files and traverse directories via crafted _state_id_ query parameters.
CVE-2026-108258 is a directory traversal vulnerability located in the bookmark state restoration component of Shiny for Python (posit-dev/py-shiny), affecting package versions from 1.4.0 up to 1.6.3.
The vulnerability exists in the URL query string processing logic used when restoring saved user session states. When an application receives a request with the _state_id_ parameter, the server constructs a local filesystem path without validating or restricting relative and absolute path sequences.
An unauthenticated remote attacker can supply relative traversal sequences or absolute paths within _state_id_ to force the application server to load state files from arbitrary directories. Under specific configurations using file uploads and server-side bookmark storage, attackers can manipulate file input restoration handlers to copy sensitive local files into web-accessible locations.
The fundamental root cause resides in shiny/bookmark/_bookmark_state.py within the _local_dir(id) path helper function. In affected releases, the function instantiated a pathlib.Path object by concatenating the current working directory, the default bookmark directory name, and the user-supplied id string extracted directly from the _state_id_ parameter.
Python's pathlib.Path operator (/) overrides preceding path elements whenever a appended component begins with a root path separator or contains relative traversal tokens such as ... Because _local_dir omitted string validation on the id argument, values such as _state_id_=../../etc or _state_id_=/etc caused path calculations to evaluate outside the intended shiny_bookmarks/ directory.
Secondary flaws compounded the exposure. In shiny/bookmark/_restore_state.py, RestoreContext.from_query_string() processed restore contexts even when bookmark_store was set to "disable". Additionally, in shiny/input_handler.py, the file restoration logic invoked shutil.copy2() without validating symbolic links or enforcing that source paths remained bounded within the target bookmark folder.
In vulnerable versions of shiny/bookmark/_bookmark_state.py, path construction relied on direct string joining without format verification:
# Vulnerable path resolution in shiny/bookmark/_bookmark_state.py
def _local_dir(id: str) -> Path:
return Path(os.getcwd()) / shiny_bookmarks_folder_name / idIn commit 1d8ecb46cbc9621b7dc8812111d26692e086b376, strict regular expression validation and length constraints were implemented through validate_bookmark_id:
_valid_bookmark_id_re = re.compile(r"[A-Za-z0-9_-]+")
_max_bookmark_id_length = 1024
def validate_bookmark_id(id: str) -> None:
if len(id) > _max_bookmark_id_length or not _valid_bookmark_id_re.fullmatch(id):
raise ValueError(f"Invalid bookmark id: {id!r}")Additionally, the patch introduced strict verification of input file sources in shiny/input_handler.py to prevent symbolic link traversal and out-of-bounds file copying:
# File restoration check in shiny/input_handler.py
def _restore_file_source(restore_dir: Path, name: str) -> Path:
src = restore_dir / name
if src.is_symlink() or not src.is_file():
raise ValueError(f"Invalid file input path: {name!r}")
if src.resolve().parent != restore_dir.resolve():
raise ValueError(f"Invalid file input path: {name!r}")
return srcExploitation is conducted by submitting an HTTP GET request containing a modified _state_id_ parameter to a target application running an affected version of Shiny for Python.
When the server receives the request, RestoreContext.from_query_string() attempts to read state files (input.json and values.json) from the path constructed by _local_dir(). If an attacker specifies a directory on the server that contains valid state files, those values are loaded into the user session.
In deployments configured with bookmark_store="server" and using ui.input_file(), file uploads restored during session initialization trigger _restore_file_source(). If an attacker references system files or symbolic links within traversed directories, shutil.copy2() copies target files into web-accessible temporary locations.
CVE-2026-108258 is assigned a CVSS v4.0 base score of 6.9 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N). The vulnerability is remotely exploitable without authentication or user interaction.
The primary impact is low-to-medium confidentiality loss. Standard web applications running default setups are vulnerable to directory probing and state file inclusion. Applications using file input components alongside server-side bookmark storage face file exposure risks if attacker-accessible state files point to local host files.
Prior to version 1.6.4, failed restoration attempts generated exception traces that were forwarded to browser notification banners via notification_show(). This exposed local system directory structures to external clients. The patch replaces client notifications with generic messages while routing technical details to server logs.
The primary remediation for CVE-2026-108258 is updating the shiny package to version 1.6.4 or later.
Package updates can be installed using pip:
pip install --upgrade shinyIf immediate package upgrading is not feasible, edge security devices or Web Application Firewalls (WAFs) should be configured to block inbound HTTP requests containing _state_id parameter values with relative path sequences (.., %2e%2e), leading slashes, or non-alphanumeric characters.
Application developers should verify that session bookmarking configurations enforce restricted state storage and monitor application logs for ValueError logs originating from shiny.bookmark._restore_state.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
shiny posit-dev | >= 1.4.0, < 1.6.4 | 1.6.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network (HTTP / WebSocket) |
| CVSS v4.0 Score | 6.9 (Medium) |
| Exploit Status | Proof of Concept / Public Patch |
| CISA KEV Status | Not Listed |
| Authentication Required | None (Unauthenticated) |
The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly sanitize the input.
An authorization bypass vulnerability in Vikunja versions prior to v2.6.0 permits authenticated users to delete relationships between tasks across project boundaries without requiring read or write authorization for the target related task.
A Stored Cross-Site Scripting vulnerability in @tinacms/web-components prior to version 0.2.1 allows low-privileged content authors to execute arbitrary JavaScript code in the context of website visitors via unsanitized URL attributes in custom Markdown rendering components.
A critical origin validation flaw in TinaCMS admin preview allows unauthenticated attackers to bypass cross-origin postMessage checks and execute unauthorized GraphQL queries and mutations under an authenticated editor's context.
@tinacms/cli prior to version 3.0.0 dynamically constructs client source files using string interpolation without properly sanitizing runtime configuration variables. An attacker with permissions to create a branch or pull request can inject arbitrary JavaScript statements via a crafted Git ref name, leading to execution during automated build processes.
Nginx UI versions 2.2.0 through 2.5.10 fail to properly configure Gin framework trusted proxies when deployed behind a reverse proxy. This causes all incoming HTTP requests to be attributed to the loopback IP (127.0.0.1), enabling IP allowlist bypass and global authentication lockouts.
Nginx UI versions 2.5.0 through 2.5.10 contain an uncontrolled resource consumption vulnerability in the node authentication handler. Unauthenticated remote attackers can exhaust host disk storage and I/O resources by submitting large HTTP request bodies to node-signature endpoints prior to cryptographic signature validation.