Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions features/flags.feature
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,18 @@ Feature: Global flags
Running SSH command: docker exec '--env MY_VAR=value' 'wordpress' sh -c
"""

@skip-windows @skip-macos
Scenario: SSH arguments with a trailing newline should be escaped
# A trailing newline used to satisfy the "safe characters" check because
# PCRE's $ anchor also matches just before a final newline, letting the
# argument reach the remote shell unquoted.
When I try `newline_arg="$(printf 'foo\nx')"; wp --debug --ssh=wordpress option get "${newline_arg%x}"`
Then STDERR should contain:
"""
Running SSH command: ssh -T -vvv 'wordpress' 'wp --debug option get '\''foo
'\'''
"""

Scenario: SSH connection string with leading hyphen in host should error
# The payload must not contain a slash, as that would be parsed as the path
# and thus separated from the host.
Expand Down
5 changes: 4 additions & 1 deletion php/WP_CLI/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,10 @@ private function run_ssh_command( string $connection_string ): void {
foreach ( $wp_args as $arg ) {
// Quote empty strings and arguments with any characters outside the safe set.
// The empty string check is explicit for clarity, though regex would also catch it.
if ( '' !== $arg && preg_match( '/^[a-zA-Z0-9_=.\/:-]+$/', $arg ) ) {
// Anchor with \A and \z rather than ^ and $: PCRE's $ also matches just before a
// trailing newline, which would let a value ending in "\n" skip escaping and smuggle
// a command separator into the remote shell command.
if ( '' !== $arg && preg_match( '/\A[a-zA-Z0-9_=.\/:-]+\z/', $arg ) ) {
$escaped_args[] = $arg;
Comment thread
swissspidy marked this conversation as resolved.
} else {
$escaped_args[] = escapeshellarg( $arg );
Expand Down
Loading