Skip to content

fix(security): suppress unhandled stdout/stderr stream errors in install policy#100413

Closed
cxbAsDev wants to merge 1 commit into
openclaw:mainfrom
cxbAsDev:fix/install-policy-stream-errors
Closed

fix(security): suppress unhandled stdout/stderr stream errors in install policy#100413
cxbAsDev wants to merge 1 commit into
openclaw:mainfrom
cxbAsDev:fix/install-policy-stream-errors

Conversation

@cxbAsDev

@cxbAsDev cxbAsDev commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

runPolicyCommand attaches data listeners to child.stdout and child.stderr, but does not attach error listeners. If either stream emits an error event, the unhandled error can crash the process or leave the policy command hanging.

Why This Change Was Made

Add no-op error handlers to both stdout and stderr streams before the data handlers, mirroring the existing stdin error handling pattern. This prevents unhandled stream errors from propagating as uncaught exceptions.

User Impact

More robust install policy execution: transient stream read errors no longer crash the OpenClaw process during skill/plugin installs.

Evidence

  • Added a regression test in src/security/install-policy.test.ts that mocks spawn, emits error events on both stdout and stderr, and verifies runInstallPolicy still resolves successfully.
  • Verified the test fails on main with an unhandled Error: stdout read failed and times out, and passes with this fix.
  • oxlint passes on the changed files.

@cxbAsDev
cxbAsDev requested a review from a team as a code owner July 5, 2026 18:28
@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 2:41 PM ET / 18:41 UTC.

Summary
The PR adds no-op stdout/stderr error listeners in runPolicyCommand and a mocked regression test for stream error events during install policy execution.

PR surface: Source +2, Tests +84. Total +86 across 2 files.

Reproducibility: yes. at source level: current main has stdout/stderr data listeners without error listeners, and Node throws unhandled error events without a listener. I did not run a full OpenClaw install-policy scenario in this read-only review.

Review metrics: 1 noteworthy metric.

  • Fail-Closed Policy Path: 1 stream-error path changed from unhandled crash to ignored error. Install policy is the operator allow/block boundary, so maintainers need to review whether stream read errors fail closed before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Change stdout/stderr stream errors to reject and fail closed.
  • [P1] Update the regression test to expect a security_scan_failed blocked result.
  • [P1] Add redacted real behavior proof, such as terminal output or logs from an install-policy run after the fix.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body cites a mocked spawn regression test and oxlint only; add redacted terminal/log/live-output proof of the real install-policy path after the fix and update the PR body to trigger re-review.

Risk before merge

  • [P1] No-op stdout/stderr error listeners can let an install continue from a policy command whose output stream failed, weakening the documented fail-closed security policy.
  • [P1] Contributor evidence is mock-only; there is no redacted live install-policy run, terminal transcript, log, or artifact showing after-fix behavior.

Maintainer options:

  1. Fail Closed On Stream Errors (recommended)
    Replace the no-op stdout/stderr handlers with a shared reject path and update the regression test to assert a failed install-policy result.
  2. Accept Ignored Stream Errors
    Maintainers could intentionally swallow output-stream errors, but that would make install policy trust potentially incomplete stdout.

Next step before merge

  • [P1] Manual follow-up is needed because the PR changes a security boundary and contributor proof is mock-only; the author should revise it to fail closed before maintainers consider merge.

Security
Needs attention: Needs attention: the diff suppresses crashes by ignoring stdout/stderr stream errors, but that can weaken install-policy fail-closed behavior.

Review findings

  • [P1] Fail closed instead of swallowing stream errors — src/security/install-policy.ts:603-605
Review details

Best possible solution:

Handle stdout/stderr stream errors through the same settle-and-reject path as child process errors so runInstallPolicy fails closed, with regression coverage that expects security_scan_failed rather than allow.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main has stdout/stderr data listeners without error listeners, and Node throws unhandled error events without a listener. I did not run a full OpenClaw install-policy scenario in this read-only review.

Is this the best way to solve the issue?

No. Adding listeners is the right direction, but no-op listeners are not the best fix for a security policy boundary; the stream errors should reject so the existing fail-closed path handles them.

Full review comments:

  • [P1] Fail closed instead of swallowing stream errors — src/security/install-policy.ts:603-605
    These no-op handlers prevent the crash, but they also let runPolicyCommand keep resolving successfully if stdout or stderr emits an error and the buffered stdout still parses as allow. security.installPolicy is the operator allow/block boundary and its docs define policy execution failures as fail-closed, so this handler should settle/reject and let runInstallPolicy return security_scan_failed instead of allowing the install.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3f380635f59b.

Label changes

Label changes:

  • add P2: This is a focused security-boundary bugfix PR for an operator install-policy edge case, with limited blast radius but merge-blocking correctness concerns.
  • add merge-risk: 🚨 security-boundary: Merging the no-op handlers could allow installs to proceed after policy stdout/stderr stream read errors instead of failing closed.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body cites a mocked spawn regression test and oxlint only; add redacted terminal/log/live-output proof of the real install-policy path after the fix and update the PR body to trigger re-review.

Label justifications:

  • P2: This is a focused security-boundary bugfix PR for an operator install-policy edge case, with limited blast radius but merge-blocking correctness concerns.
  • merge-risk: 🚨 security-boundary: Merging the no-op handlers could allow installs to proceed after policy stdout/stderr stream read errors instead of failing closed.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body cites a mocked spawn regression test and oxlint only; add redacted terminal/log/live-output proof of the real install-policy path after the fix and update the PR body to trigger re-review.
Evidence reviewed

PR surface:

Source +2, Tests +84. Total +86 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 0 +2
Tests 1 84 0 +84
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 86 0 +86

Security concerns:

  • [high] Install policy stream errors are ignored — src/security/install-policy.ts:603
    The proposed no-op handlers can convert a policy output read failure into a successful allow decision, which weakens a security boundary that should fail closed on policy execution failure.
    Confidence: 0.86

What I checked:

Likely related people:

  • steipete: git blame and PR metadata show the install-policy runner, its docs, and the scan caller came from 2bc50d0656bd3c5905f0d972ff429c8388c43b9e / feat: verify AI access during macOS onboarding before the first chat #100288. (role: feature-history owner; confidence: high; commits: 2bc50d0656bd, c757675f348d; files: src/security/install-policy.ts, src/security/install-policy.test.ts, src/plugins/install-security-scan.runtime.ts)
  • openclaw/openclaw-secops: .github/CODEOWNERS assigns src/security/ to this security review team, and this PR changes that security-sensitive path. (role: CODEOWNERS review owner; confidence: high; files: .github/CODEOWNERS, src/security/install-policy.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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 keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 5, 2026
@steipete steipete self-assigned this Jul 5, 2026
steipete added a commit that referenced this pull request Jul 5, 2026
steipete added a commit that referenced this pull request Jul 5, 2026
* fix(agents): harden LSP process failures

Source: #100450

Co-authored-by: morluto <[email protected]>

* fix(sandbox): report effective workspace layout

Sources: #100435, #100439

Co-authored-by: Aniruddha Adak <[email protected]>

Co-authored-by: ZengWen-DT <[email protected]>

* fix(security): fail install checks on stream errors

Source: #100413

Co-authored-by: 陈宪彪0668000387 <[email protected]>

* fix(android): normalize all-day calendar events

Source: #100032

Co-authored-by: NianJiuZst <[email protected]>

* fix(ios): serialize push-to-talk lifecycle

Source: #99942

Co-authored-by: NianJiuZst <[email protected]>

* fix(talk): reject inherited provider names

Source: #99849

Co-authored-by: zenglingbiao <[email protected]>

* fix(android): stop voice capture in background

Source: #99840

Co-authored-by: xialonglee <[email protected]>

* fix(cron): preserve fallback result classification

Source: #99913

Co-authored-by: jincheng-xydt <[email protected]>

* fix(google): bound Vertex response decompression

Source: #99812

Co-authored-by: 黄剑雄0668001315 <[email protected]>

* fix(plugins): report malformed discovery JSON

Source: #99892

Co-authored-by: 陈宪彪0668000387 <[email protected]>

* test(sandbox): configure non-default workspace fixture

* test: fix small-fix batch validation

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: ZengWen-DT <[email protected]>
Co-authored-by: 陈宪彪0668000387 <[email protected]>
Co-authored-by: NianJiuZst <[email protected]>
Co-authored-by: zenglingbiao <[email protected]>
Co-authored-by: xialonglee <[email protected]>
Co-authored-by: jincheng-xydt <[email protected]>
Co-authored-by: 黄剑雄0668001315 <[email protected]>
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Thanks @cxbAsDev — your stream-error finding was incorporated into the fail-closed canonical fix in #100483, landed as aaf5ab9. The landed version covers stdout, stderr, and stdin failures, kills the policy process tree where required, and proves partial allow output cannot escape a later stream failure. Contributor credit is preserved. Closing this superseded PR.

@steipete steipete closed this Jul 5, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
* fix(agents): harden LSP process failures

Source: openclaw#100450

Co-authored-by: morluto <[email protected]>

* fix(sandbox): report effective workspace layout

Sources: openclaw#100435, openclaw#100439

Co-authored-by: Aniruddha Adak <[email protected]>

Co-authored-by: ZengWen-DT <[email protected]>

* fix(security): fail install checks on stream errors

Source: openclaw#100413

Co-authored-by: 陈宪彪0668000387 <[email protected]>

* fix(android): normalize all-day calendar events

Source: openclaw#100032

Co-authored-by: NianJiuZst <[email protected]>

* fix(ios): serialize push-to-talk lifecycle

Source: openclaw#99942

Co-authored-by: NianJiuZst <[email protected]>

* fix(talk): reject inherited provider names

Source: openclaw#99849

Co-authored-by: zenglingbiao <[email protected]>

* fix(android): stop voice capture in background

Source: openclaw#99840

Co-authored-by: xialonglee <[email protected]>

* fix(cron): preserve fallback result classification

Source: openclaw#99913

Co-authored-by: jincheng-xydt <[email protected]>

* fix(google): bound Vertex response decompression

Source: openclaw#99812

Co-authored-by: 黄剑雄0668001315 <[email protected]>

* fix(plugins): report malformed discovery JSON

Source: openclaw#99892

Co-authored-by: 陈宪彪0668000387 <[email protected]>

* test(sandbox): configure non-default workspace fixture

* test: fix small-fix batch validation

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: ZengWen-DT <[email protected]>
Co-authored-by: 陈宪彪0668000387 <[email protected]>
Co-authored-by: NianJiuZst <[email protected]>
Co-authored-by: zenglingbiao <[email protected]>
Co-authored-by: xialonglee <[email protected]>
Co-authored-by: jincheng-xydt <[email protected]>
Co-authored-by: 黄剑雄0668001315 <[email protected]>
@cxbAsDev
cxbAsDev deleted the fix/install-policy-stream-errors branch July 15, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants