VAITP Dataset

← Back to the dataset

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.

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_path

Patched 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 True

Payload

~/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 ::