Skip to content

fix(shell): don't let non-UTF-8 command output kill the playbook - #259

Merged
whotwagner merged 1 commit into
ait-testbed:developmentfrom
VainXploits:fix/shell-executor-decode-errors
Sep 7, 2026
Merged

fix(shell): don't let non-UTF-8 command output kill the playbook#259
whotwagner merged 1 commit into
ait-testbed:developmentfrom
VainXploits:fix/shell-executor-decode-errors

Conversation

@VainXploits

@VainXploits VainXploits commented Sep 4, 2026

Copy link
Copy Markdown

ShellExecutor decoded command output with a strict UTF-8 decode. Command output is arbitrary bytes, so any command emitting a non-UTF-8 byte raised UnicodeDecodeError. Nothing catches it between _exec_cmd and main(), so the exception terminates the entire playbook rather than failing the one step.

Both read paths are affected: popen_noninteractive on its combined stdout+stderr, and popen_interactive on its non-blocking read.

Use errors='replace' so undecodable bytes become U+FFFD and execution continues. Output is used for logging, error_if/error_if_not matching and save-to-file; none of those require a lossless round-trip, and a replacement character is strictly more useful than losing the run.

Adds three regression tests, one per read path plus an end-to-end shell execution. All three fail on the strict decode and pass with the fix.

Encountered with a PHP filter-chain response containing 0xc9, which ended a 40-step playbook at step 6.

Task

Description

How Has This Been Tested?

Checklist

  • This Pull-Request goes to the development branch.
  • I have successfully run prek locally.
  • I have added tests to cover my changes.
  • I have linked the issue-id to the task-description.
  • I have performed a self-review of my own code.

ShellExecutor decoded command output with a strict UTF-8 decode. Command
output is arbitrary bytes, so any command emitting a non-UTF-8 byte raised
UnicodeDecodeError. Nothing catches it between _exec_cmd and main(), so the
exception terminates the entire playbook rather than failing the one step.

Both read paths are affected: popen_noninteractive on its combined
stdout+stderr, and popen_interactive on its non-blocking read.

Use errors='replace' so undecodable bytes become U+FFFD and execution
continues. Output is used for logging, error_if/error_if_not matching and
save-to-file; none of those require a lossless round-trip, and a replacement
character is strictly more useful than losing the run.

Adds three regression tests, one per read path plus an end-to-end shell
execution. All three fail on the strict decode and pass with the fix.

Encountered with a PHP filter-chain response containing 0xc9, which ended a
40-step playbook at step 6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTrxUy2RcoHv723hVynSo8

@whotwagner whotwagner 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.

Would you mind to make this pull request for the development branch?

@VainXploits
VainXploits changed the base branch from main to development September 5, 2026 09:53
@VainXploits

Copy link
Copy Markdown
Author

Hey there! Just changed the branch to development! I have a few more features that I'm working on coming in soon haha

@whotwagner

Copy link
Copy Markdown
Contributor

Hey there! Just changed the branch to development! I have a few more features that I'm working on coming in soon haha

nice. i am looking forward

@whotwagner
whotwagner merged commit 62f4e62 into ait-testbed:development Sep 7, 2026
1 check passed
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.

2 participants