Aug 26, 2026·6 min read·2 visits
An incomplete path-traversal fix in AsyncSSH allows unauthenticated remote attackers to escape AuthorizedKeysFile directories using tilde expansion and environment variable manipulation, enabling potential authentication bypass.
An incomplete input sanitization fix in AsyncSSH version 2.23.0 allows unauthenticated remote attackers to bypass directory restriction controls and perform path-traversal attacks. When the system is configured to perform username token substitution inside its AuthorizedKeysFile directive, attackers can manipulate downstream path resolution mechanisms via tilde expansion and environment variable references. This flaw permits authentication bypasses by forcing the server to read public keys from unauthorized file locations outside the restricted environment.
AsyncSSH is an asynchronous client and server implementation of the SSHv2 protocol, developed on top of Python's asyncio framework. The framework is commonly utilized in custom SSH services, automation tooling, and cloud controller nodes. Within this architecture, the server configurations handle dynamic client-supplied strings, including username data, which are evaluated during the public-key authentication phase.
When configured with the AuthorizedKeysFile directive containing the %u token, the library performs string substitution using the client-supplied username. In version 2.23.0, developers implemented a sanitization mechanism to prevent directory traversal exploits, originally discovered under CVE-2026-45309. This block-list validation checked for directory separators and parent directory indicators to ensure username expansion remained within a designated keys directory.
However, this sanitization check was functionally incomplete and failed to address alternative path-traversal avenues. By supplying usernames crafted with tilde user indicators or environment variable tokens, remote attackers can bypass the initial sanitization boundary. The server subsequently resolves these strings into paths outside the restricted base directory, leading to unauthorized public key evaluations.
The underlying vulnerability arises from the sequencing of input validation relative to file path resolution. In AsyncSSH v2.23.0, the validation in SSHServerConfig._set_tokens checked the incoming self._user string to ensure it was not equal to .. and did not contain the / or \ characters. This logic successfully blocked basic relative traversal paths like ../../ but did not account for downstream path-resolution operations.
During subsequent path resolution, Python's native pathlib.Path library is invoked, which calls the expanduser() method. In a standard operating environment, Path('~root/.ssh/authorized_keys').expanduser() evaluates the leading tilde token and expands to the home directory of the root user. Because the string ~root contains no slashes and is not equal to .., it completely bypasses the v2.23.0 sanitization block and escapes the intended authorized-keys folder.
Furthermore, the application performs recursively evaluated environment variable expansion via _expand_val. An attacker can supply a username consisting of an environment variable lookup, such as ${HOME}. Because this input is evaluated and expanded after the character-level sanitization step, the resulting absolute folder path contains slashes that are never subjected to security validation, enabling directory escapes.
The vulnerable code path in asyncssh/config.py at version 2.23.0 relied on a simple conditional block that only analyzed raw string matching. This is illustrated in the snippet below:
# Vulnerable validation logic in v2.23.0
if self._user == '..' or '/' in self._user or '\\' in self._user:
raise IllegalUserName('Unsafe username substitution')To correct this deficiency, version 2.23.1 transitioned to an explicit regular expression pattern named _unsafe_user_pattern to evaluate incoming usernames. The updated validation logic verifies multiple expansion types, as shown below:
# Patched validation logic in v2.23.1
_unsafe_user_pattern = re.compile(r'^\.\.$|^~|^[A-Za-z]:|[\\/]|\$\{.*?\}')
def _set_tokens(self) -> None:
"""Set the tokens available for percent expansion"""
if _unsafe_user_pattern.search(self._user):
raise IllegalUserName('Unsafe username substitution')
self._tokens.update({'u': self._user})The introduction of _unsafe_user_pattern addresses all four bypass vectors. First, ^~ blocks any leading tilde to prevent home directory expansion. Second, ^[A-Za-z]: blocks Windows drive letter targets. Third, \$\{.*?\} matches environment variable syntax to prevent delayed evaluation exploits. Finally, forward and backward slashes continue to be intercepted.
Exploitation of this vulnerability requires that the target SSH server is configured with dynamic username path mapping. This occurs when the AuthorizedKeysFile directive utilizes the %u substitution token. The target must be running version 2.23.0 of AsyncSSH, where the directory-traversal block-list is active but incomplete.
During authentication, the unauthenticated client initiates a connection and submits a crafted username string, such as ~root. The server receives this connection request and routes the username through the substitution engine. The target file path template, e.g., /var/lib/ssh/keys/authorized_keys_%u, is updated to /var/lib/ssh/keys/authorized_keys_~root.
When the system attempts to open this path, Python's path-resolution libraries process the path using user-expansion procedures. The operating system resolves the trailing ~root suffix to the actual root directory path /root. The server evaluates the keys under this root directory instead of the restricted public-key repository, matching the attacker's key against keys stored in alternative folders, which can lead to an authentication bypass.
The impact of CVE-2026-54590 is significant for environments leveraging multi-tenant or containerized SSH environments with dynamic configuration lookups. Successful exploitation allows an attacker to manipulate file path resolution. This capability permits attackers to redirect the key lookup process to file paths containing public keys under their control or to read globally readable files.
The CVSS v3.1 base score is calculated at 5.9 (Medium severity). The Attack Complexity is classified as High (AC:H) because exploitation depends on the server utilizing %u within the AuthorizedKeysFile configuration, and the target operating system must support the corresponding user-expansion or environment variable lookup.
The Integrity impact of this vulnerability is High (I:H) because bypassing authorized-key limitations directly compromises the authentication boundary of the SSH server. However, there is no direct impact on Confidentiality (C:N) or Availability (A:N), as the traversal vector is limited to altering file resolution targets rather than achieving direct arbitrary file extraction or service denial.
The recommended remediation is upgrading the asyncssh package to version 2.23.1 or newer. The update fully patches the path validation logic inside config.py by incorporating regex-based input auditing that neutralizes tilde expansion, environment variables, and Windows-specific drive designations before variable expansion.
If patching the library is not immediately possible, administrators can mitigate the risk by modifying server configuration files. Disabling the use of the %u username substitution token inside the AuthorizedKeysFile directive will prevent the vulnerability. Implementing static, absolute directories for public keys prevents users from influencing the filesystem resolution paths.
Furthermore, enforcing the principle of least privilege on the runtime environment of the application is a key defense-in-depth practice. Running the asyncssh server daemon inside a sandboxed, unprivileged container with a read-only filesystem limits the availability of target system accounts and directory structures, reducing the likelihood of a successful traversal escape.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
asyncssh ronf | <= 2.23.0 | 2.23.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network |
| CVSS | 5.9 (Medium) |
| EPSS Score | 0.00393 |
| Impact | Integrity (High) |
| Exploit Status | Proof of Concept |
| KEV Status | Not Listed |
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.
CVE-2026-54614 is an unsafe reflection vulnerability in the MailPreview component of cakephp/debug_kit prior to versions 4.10.3 and 5.2.4. Unauthenticated or low-privileged remote attackers can exploit this vulnerability to dynamically resolve and instantiate arbitrary PHP classes within the Composer autoloader environment, leading to constructor and destructor execution.
CVE-2026-54591 is a high-severity path traversal vulnerability in AsyncSSH's SCP implementation prior to version 2.23.1. When an AsyncSSH-based SCP client connects to a malicious or compromised SSH server and performs a file transfer, the server can send crafted filenames containing relative path sequences. Because the client failed to validate these filenames before resolving the final storage path, a malicious server could write or overwrite arbitrary files on the client machine within the security context of the executing application. This vulnerability is mapped to GitHub Security Advisory GHSA-2wxc-x7rj-hg8f.
An unrestricted file upload vulnerability exists in the Pollen Robotics Reachy Mini robot daemon prior to version 1.8.2. Unauthenticated remote attackers can upload arbitrary files to the temporary sounds directory over the network, leading to disk pollution and staging for potential secondary local exploits.
CVE-2026-55637 is a high-severity DNS rebinding vulnerability affecting the genieacs-mcp Model Context Protocol server. Prior to version 0.3.2, the application's Streamable HTTP transport lacks adequate Host and Origin header validation. This omission allows external attackers to bypass the Same-Origin Policy through a victim's browser and issue unauthenticated commands to loopback listeners.
A critical vulnerability exists in the elixir-grpc library's Erlpack codec, where the unsafe deserialization of Erlang External Term Format (ETF) payloads allows unauthenticated remote attackers to cause a Denial of Service through atom table exhaustion or execute arbitrary code on the host server.
An authorization bypass vulnerability exists in the elixir-grpc/grpc library version 0.8.0 up to 1.0.0. Due to insecure map merging precedence inside the HTTP-to-gRPC transcoding engine, query-string parameters and request bodies can override routing path variables, allowing attackers to execute unauthorized actions on other accounts.