Skip to content

Anchor SSH argument safe-set check with \A..\z to reject trailing newlines - #6384

Merged
swissspidy merged 2 commits into
mainfrom
claude/wp-cli-security-scan-pf25iy
Aug 6, 2026
Merged

Anchor SSH argument safe-set check with \A..\z to reject trailing newlines#6384
swissspidy merged 2 commits into
mainfrom
claude/wp-cli-security-scan-pf25iy

Conversation

@swissspidy

@swissspidy swissspidy commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

When run_ssh_command() assembles the command to run on the remote host, each argument is passed through unquoted when it matches a "safe characters" allowlist, and is otherwise wrapped in escapeshellarg(). That allowlist regex was anchored with ^…$.

In PCRE, $ also matches immediately before a trailing newline, so an argument ending in "\n" matched the "safe" pattern and was emitted raw into the remote shell command — where the newline acts as a command separator.

This changes the anchors to \A…\z (which assoc_args_to_str() already uses), so any value containing a newline is routed through escapeshellarg().

Impact

Defense-in-depth only — not known to be exploitable. The arguments here come from the operator's own argv (array_slice( $GLOBALS['argv'], 1 )), so there is no lower-privilege source that can introduce a newline. The change removes a latent quoting bypass and makes newline anchoring consistent with the rest of the codebase.

Behavior

Only arguments containing a newline change behavior (now escaped); normal arguments are unaffected:

arg old (^…$) new (\A…\z)
user passed raw passed raw
--url=https://e.com/p passed raw passed raw
"foo\n" passed raw ⚠️ escaped
"a\nb" escaped escaped

🤖 Generated with Claude Code

https://claude.ai/code/session_01LV1bNtxNCZ3QXujJHYfhZv


Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved SSH command validation to prevent trailing newline characters from bypassing safety checks and enabling unintended shell command injection.
    • Added coverage to verify safe handling of trailing newlines in SSH command arguments.

When assembling the remote command in `run_ssh_command()`, an argument is
passed through unquoted when it matches the "safe characters" pattern.
That pattern used `^...$`, but PCRE's `$` also matches immediately before a
trailing newline, so a value ending in "\n" was considered safe and
emitted raw into the remote shell command — where the newline acts as a
command separator.

Anchor the pattern with `\A` and `\z` (as `assoc_args_to_str()` already
does) so any value containing a newline is routed through `escapeshellarg()`.

This is not known to be exploitable today — the arguments here come from
the operator's own argv — but it removes a latent quoting bypass and makes
the anchoring consistent across the codebase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LV1bNtxNCZ3QXujJHYfhZv
@swissspidy
swissspidy requested a review from a team as a code owner August 5, 2026 20:19
Copilot AI lite review requested due to automatic review settings August 5, 2026 20:19
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a937240b-4c00-4026-b608-cb6b48d018a1

📥 Commits

Reviewing files that changed from the base of the PR and between ad1203e and fe92721.

📒 Files selected for processing (1)
  • features/flags.feature

📝 Walkthrough

Walkthrough

The SSH argument safety check now uses PCRE absolute anchors. Arguments that end with a newline no longer bypass escaping. A feature scenario verifies the behavior.

Changes

SSH argument safety

Layer / File(s) Summary
Absolute pattern validation
php/WP_CLI/Runner.php, features/flags.feature
The safe-character pattern uses \A and \z instead of ^ and $. The regression scenario verifies that trailing-newline arguments remain safely quoted.

Estimated code review effort: 2 (Simple) | ~5 minutes

Possibly related PRs

Suggested labels: scope:framework, bug

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: anchoring the SSH argument safety check to reject trailing newlines.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wp-cli-security-scan-pf25iy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request hardens WP-CLI’s SSH execution path by ensuring arguments that end with a trailing newline are not incorrectly treated as “safe” and emitted unquoted into the remote shell command.

Changes:

  • Replaces the safe-argument allowlist anchors from ^…$ to \A…\z in Runner::run_ssh_command() to prevent $ matching before a trailing newline.
  • Adds inline rationale explaining the PCRE anchoring edge case and the remote-shell command-separator risk.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread php/WP_CLI/Runner.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
php/WP_CLI/Runner.php (1)

1047-1050: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for trailing-newline arguments.

Add a test that passes an argument ending in "\n" through run_ssh_command() and verifies that it is escaped instead of emitted as a raw command separator. The existing validation test does not cover this exact path.

As per coding guidelines, run composer test before submitting changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@php/WP_CLI/Runner.php` around lines 1047 - 1050, Add a regression test
covering run_ssh_command() with an argument ending in "\n", asserting the
newline-containing value is escaped rather than emitted as a raw command
separator. Keep the existing validation coverage intact and run composer test to
verify the change.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@php/WP_CLI/Runner.php`:
- Around line 1047-1050: Add a regression test covering run_ssh_command() with
an argument ending in "\n", asserting the newline-containing value is escaped
rather than emitted as a raw command separator. Keep the existing validation
coverage intact and run composer test to verify the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 568ddf8f-8679-465e-8439-3b7f194ece79

📥 Commits

Reviewing files that changed from the base of the PR and between 43ed1f1 and ad1203e.

📒 Files selected for processing (1)
  • php/WP_CLI/Runner.php

@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Covers the \A..\z anchor change in run_ssh_command(): an argument with a
trailing newline must be routed through escapeshellarg() instead of being
emitted raw into the remote shell command.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PyYsgTUw9BZvzptwJVoRnh
@swissspidy swissspidy added this to the 3.0.0 milestone Aug 6, 2026
@swissspidy
swissspidy merged commit 847a2c1 into main Aug 6, 2026
74 checks passed
@swissspidy
swissspidy deleted the claude/wp-cli-security-scan-pf25iy branch August 6, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants