@@ -502,17 +502,16 @@ async def openssh_execute(self, commands, stdin: Optional[str] = None, timeout:
502502 return process .returncode , stdout .decode (), stderr .decode ()
503503
504504 def _escape_for_rcp (self , path : str ) -> str :
505- """Escape special characters for scp RCP mode using backslashes .
505+ """Backslash-escape shell metacharacters for scp's RCP protocol .
506506
507- Note: escape_for_bash() does NOT work here because scp's RCP protocol
508- expects backslash-escaped paths, not quote-wrapped strings.
507+ Glob characters (``*``, ``?``, ``[``, ``]``) are deliberately left
508+ unescaped so the remote shell expands them; the trade-off is that
509+ filenames containing literal glob characters cannot be addressed
510+ in RCP mode. :func:`escape_for_bash` is unsuitable here because it
511+ quote-wraps rather than backslash-escapes.
509512
510- Important: We do NOT escape glob characters (*, ?, []) because the RCP
511- protocol passes these to the remote shell for glob expansion. Escaping
512- them would prevent proper file pattern matching.
513-
514- :param path: The path to escape
515- :return: The escaped path with backslashes before special characters
513+ :param path: The path to escape.
514+ :return: The escaped path.
516515 """
517516
518517 result = []
@@ -526,20 +525,13 @@ def _escape_for_rcp(self, path: str) -> str:
526525 def _escape_for_scp (self , path : str ) -> str :
527526 """Prepare a path for use in scp commands.
528527
529- Version-specific behavior:
530-
531- - OpenSSH 9.0+ (SFTP mode):
532- Uses SFTP protocol where paths are treated as binary data.
533- No escaping needed - glob characters are not expanded.
534- Direct return of the path.
535-
536- - OpenSSH < 9.0 (RCP mode):
537- Uses RCP protocol where paths are passed to remote shell.
538- Must escape shell metacharacters to prevent injection,
539- but MUST preserve glob characters (*, ?, []) for proper
540- file pattern matching.
541-
542- Version detection is based on `is_openssh_9_or_higher` flag set in __init__.
528+ OpenSSH >= 9.0 uses SFTP mode: paths are sent as binary, no
529+ escaping needed. OpenSSH < 9.0 uses RCP mode: paths are interpreted
530+ by a shell on both ends (scp itself shells out internally for local
531+ paths), so shell metacharacters are backslash-escaped via
532+ :meth:`_escape_for_rcp` while glob characters are deliberately
533+ preserved for pattern matching. Mode is selected via
534+ :attr:`is_openssh_9_or_higher`.
543535 """
544536
545537 if self .is_openssh_9_or_higher :
0 commit comments