CVE-2026-54590
AsyncSSH path traversal vulnerability allows escaping the authorized-keys dir.
- CVSS 5.9
- CWE-22
- Input Validation and Sanitization
- Remote
AsyncSSH is a Python package which provides an asynchronous client and server implementation of the SSHv2 protocol on top of the Python asyncio framework. Version 2.23.0 contains an incomplete fix for CVE-2026-45309 in SSHServerConfig._set_tokens that blocks /, , and .. before %u substitution in AuthorizedKeysFile but does not block a leading ~ or ${ENV}, allowing later expansion in _expand_val and Path(filename).expanduser() to escape the intended authorized-keys directory. This issue is fixed in version 2.23.1.
- CWE
- CWE-22
- CVSS base score
- 5.9
- Published
- 2026-07-08
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Check
- Category
- Input Validation and Sanitization
- Subcategory
- Path Traversal
- Accessibility scope
- Remote
- Impact
- Unauthorized Access
- Affected component
- AsyncSSH
- Fixed by upgrading
- Yes
Solution
Upgrade AsyncSSH to version 2.23.1 or later.
Vulnerable code sample
import os
from pathlib import Path
def _get_authorized_keys_path_vulnerable(path_token: str, username: str) -> Path:
"""
Represents the vulnerable logic in AsyncSSH < 2.23.1 where
'AuthorizedKeysFile' is processed.
"""
# 1. Incomplete validation: The code blocks some directory traversal
# characters but crucially misses '~' and '${...}' which are used for
# shell-like expansion. This check happens before %u substitution.
if '/' in path_token or '\\' in path_token or '..' in path_token:
raise ValueError("Path contains invalid characters")
# The path token is now incorrectly considered "safe".
# 2. Unsafe Expansion: Later in the code flow, the "safe" token is
# expanded, allowing an escape from the intended base directory.
# First, substitute %u with the username
path_after_user_sub = path_token.replace('%u', username)
# Next, expand environment variables like ${HOME}
path_after_env_expand = os.path.expandvars(path_after_user_sub)
# Finally, expand the user's home directory ('~'). This is the step
# that can turn a relative path into an absolute one, thereby
# escaping any intended parent directory for authorized keys.
final_path = Path(path_after_env_expand).expanduser()
# The server would then use this `final_path`. If an attacker provided
# a path like "~/.ssh/malicious_keys", `final_path` becomes an
# absolute path to that file, bypassing the server's key directory.
return final_pathPatched code sample
import re
def _validate_authorized_keys_token(token: str):
"""
This function represents the fixed validation logic for CVE-2026-54590.
The vulnerability was that `~` and `$` were not blocked, allowing
path expansion to escape the intended directory. This function includes
the corrected checks that were added in the patched version.
"""
# The original (incomplete) fix blocked directory separators and traversal.
if '/' in token or '\\' in token or '..' in token:
raise ValueError("Path traversal characters (/, \\, ..) are not allowed.")
# --- START OF THE FIX for CVE-2026-54590 ---
# FIX: Block the tilde character to prevent user home directory expansion
# by a later call to a function like `Path.expanduser()`.
# This check was missing in the vulnerable version.
if token.startswith('~'):
raise ValueError("Path expansion with '~' is not allowed.")
# FIX: Block the dollar sign to prevent environment variable expansion
# (e.g., '${HOME}') by a later call to a function like `os.path.expandvars()`.
# This check was also missing in the vulnerable version.
if '$' in token:
raise ValueError("Environment variable expansion with '$' is not allowed.")
# --- END OF THE FIX ---
# If all checks pass, the token is considered safe to be used
# in a path, as it can no longer be expanded to an arbitrary location.
return TruePayload
~/path/to/attacker/controlled/authorized_keys
Cite this entry
@misc{vaitp:cve202654590,
title = {{AsyncSSH path traversal vulnerability allows escaping the authorized-keys dir.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-54590},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-54590/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
