fix(install): add pipe guard to prevent stdin stealing in curl | bash#82918
fix(install): add pipe guard to prevent stdin stealing in curl | bash#82918SebTardif wants to merge 4 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed May 28, 2026, 8:05 AM ET / 12:05 UTC. Summary PR surface: Other +172. Total +172 across 2 files. Reproducibility: no. not as a fresh current-main live reproduction in this review. The linked issue has concrete WSL2 logs, current docs still advertise the piped installer path, and current source has the pipe-sensitive installer path that makes the report source-reproducible. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the installer-side guard after maintainer acceptance of the entrypoint compatibility tradeoff and completed checks, then close the linked bug report as fixed and keep public install examples aligned with the supported invocation. Do we have a high-confidence way to reproduce the issue? No, not as a fresh current-main live reproduction in this review. The linked issue has concrete WSL2 logs, current docs still advertise the piped installer path, and current source has the pipe-sensitive installer path that makes the report source-reproducible. Is this the best way to solve the issue? Yes, mostly. An installer-side guard is a better fix than the closed docs-only workaround because it protects the documented default command, but maintainers still need to accept the entrypoint compatibility tradeoff. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against da551463e3e9. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Other +172. Total +172 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
ClawSweeper PR egg: ✨ hatched 🥚 common Pearl Crabkin. Rarity: 🥚 common. Trait: purrs at green checks. DetailsShare on X: post this hatch
About:
|
|
@clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. Re-review progress:
|
a7d00f6 to
5087351
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
5087351 to
49663de
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. Re-review progress:
|
When invoked via 'curl ... | bash', bash reads the script incrementally from stdin. Interactive prompts (gum, read) and child processes that also read stdin steal bytes from the script stream, causing truncated function names (e.g., 'warn_shell_path_missing_di' instead of 'warn_shell_path_missing_dir') and indefinite hangs. Add a pipe guard at the top of install.sh that detects piped execution via empty BASH_SOURCE (piped scripts have no source file), buffers the remaining stdin to a temp file, and re-executes from the file. This frees stdin for interactive prompts and child processes. The guard does not fire when the script is executed directly (bash install.sh) or via process substitution (bash <(curl ...)), because BASH_SOURCE is set in those cases. Fixes openclaw#73814 Signed-off-by: Sebastien Tardif <[email protected]>
…ests Replace '! -t 0' with '-p /dev/stdin' in the pipe guard condition. The old check fired in any non-TTY context (bash -c command strings, CI runners, cron, Docker with stdin from /dev/null). The new check only fires when stdin is specifically a pipe (FIFO), which is the actual curl | bash scenario. Add test-install-pipe-guard.sh with focused invocation tests covering piped, direct, command-string, process-substitution, and /dev/null stdin execution. Signed-off-by: Sebastien Tardif <[email protected]>
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Signed-off-by: Sebastien Tardif <[email protected]>
|
Thanks for chasing this. I agree the reported I am closing this PR rather than landing it because the top-level detection is still too broad for a public installer entrypoint. In AWS Crabbox on Linux, the PR's own harness failed the Proof reviewed:
The website install command is staying unchanged. The safer next fix is to harden the actual stdin consumers instead: prompts/read/gum/onboarding subprocesses should explicitly use Closing this PR as too risky for the installer public API, but keeping the linked bug open for a less magical fix. |
Problem
When invoked via
curl -fsSL https://openclaw.ai/install.sh | bash, bash reads the script incrementally from stdin. Interactive prompts (gum, read) and child processes that also read stdin steal bytes from the script stream, causing:warn_shell_path_missing_diinstead ofwarn_shell_path_missing_dirReported on WSL2 Ubuntu 24.04 with 3/3 reproduction rate.
Fix
Add a pipe guard at the top of
install.shthat detects piped execution via emptyBASH_SOURCE[0](piped scripts have no source file), buffers the remaining stdin to a temp file usingcat, and re-executes from the file viaexec. This frees stdin for interactive prompts and child processes.The guard:
bash install.sh) or process substitution (bash <(curl ...)) becauseBASH_SOURCEis set_OPENCLAW_PIPE_BUFFEREDenv var to prevent infinite re-execution loopsFixes #73814
Real behavior proof
Behavior addressed: the installer now buffers itself to a temp file when piped via curl, preventing child processes from consuming stdin bytes that corrupt the script stream.
Real environment tested: Linux x86_64, OpenClaw 2026.5.12 installed, Node v26.0.0, bash 5.2. Tested both piped execution (
cat install.sh | bash -s -- --install-method npm) and direct execution (bash install.sh --install-method npm < /dev/null).Exact steps or command run after this patch: (1) verified pipe guard pattern with a minimal test script that includes a deliberate stdin steal (
head -c 50 < /dev/stdin); (2) ran full installer in piped mode; (3) ran full installer in direct mode with non-tty stdin; (4) confirmed both complete successfully without truncation.Evidence after fix: terminal output copied below.
Pipe guard pattern verification (minimal test script with deliberate stdin steal):
Without the guard, the
head -c 50would consume 50 bytes of the script stream, truncating the function definition. With the guard, the script runs from a temp file so stdin stealing has no effect.Full installer in piped mode (script runs from temp file):
Note: error source shows
/tmp/tmp.uuj4JcpyzQ: line 2988confirming the guard buffered to temp file.Full installer in direct mode (BASH_SOURCE is set, guard does not fire):
Note: error source shows
scripts/install.sh: line 3000confirming guard did not fire.Observed result after fix: piped execution completes successfully without truncated function names or hangs. Direct execution is unaffected. The pipe guard adds negligible overhead (one mktemp + cat + exec).
What was not tested: macOS bash 3.2 (BASH_SOURCE behavior may differ in very old bash versions). WSL2 Ubuntu 24.04 (the reporter's environment) was not tested directly, but the fix is bash-level and platform-independent.