Skip to content

chore: preserve sandbox startup on private test desktops - #1791

Merged
shanselman merged 25 commits into
openclaw:mainfrom
paulcam206:draft/hub-desktop-harness
Oct 30, 2026
Merged

shanselman merged 25 commits into
openclaw:mainfrom
paulcam206:draft/hub-desktop-harness

Conversation

@paulcam206

@paulcam206 paulcam206 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes: an intended restricted SDK process can fail USER32 initialization when a newly owned private test desktop lacks the required package rights and integrity label.

User Impact

Developers can validate startup on exclusively task-owned desktops while preserving existing denies and caller-token restrictions. This is a test-harness change, not a new product capability or a promise of desktop isolation.

Why This Change Was Made

Complete only the missing package write/create rights and Low no-write-up label on a newly owned NULL-security desktop. Reject existing write/create denies before child creation. SDK 1.0.0 can inherit the caller's task desktop; inspect its actual assignment instead of treating requested UI policy as an isolation boundary.

The former SDK-isolation documentation claim is corrected in exact published head 15cd728cb8d3833c266e089e9aae3486dab28444. That followup changes prose only; launcher/security owners are unchanged from fe5bdafe.

Evidence

Current-head live authority proof: PASS, using an exact clean 15cd728cb8d3833c266e089e9aae3486dab28444 guest checkout, not a source overlay.

  • Admission: the actual scripts\Invoke-PrivateDesktop.ps1 launcher ran the current harness through published SDK 1.0.0. The native child was an AppContainer at Low integrity; Windows AccessCheck allowed caller-desktop write/create, USER32 initialized, and the command exited 0 without timing out. The observed assigned desktop equaled the newly owned caller desktop. This SDK positive executed once.
  • Existing-deny rejection: a new exclusively owned window station supplied an inheritable 0x82 deny for Restricted Code SID S-1-5-12. A live desktop readback and Windows AccessCheck on a genuinely restricted token allowed read but denied write objects and create window. The actual launcher then encountered an identical live-created denied DACL and rejected it with its existing write/create-denial error before child creation: no successful-child launch receipt or forbidden-child sentinel.
  • Teardown: the positive child exited; positive, denied and reference desktops and the owned station were removed. The proof process token-default DACL was restored and byte-read back. The original process window station and thread desktop were preserved. WinSta0 Default's DACL and mandatory label were unchanged. Eight owned scheduled tasks were unregistered; the parent released the exact guest lease and verified VM absence and unchanged parent VHDX metadata.

Boundary: the negative token was genuinely restricted, not an AppContainer. The launcher was not run as that token: the token authorization check and actual launcher's fail-closed guard on the matching DACL are distinct, linked observations. This establishes the bounded admission/rejection/teardown contract, not separate-desktop isolation, a full SDK matrix, ETW attribution, or absence of dialogs.

Actual guest terminal showing exact-head admission, live denied-token authorization, launcher rejection before child creation and teardown

This is an actual rendered guest-console capture (CopyFromScreen), not a generated terminal image. The normal fork asset commit has parent ed1444b0; anonymous GET returned HTTP 200 and image bytes matched SHA256 0278730E537F84D516DA29431DCCD9906E2AADE8256A664CCFAF55E845D6D33B. GitHub's upstream attachment permission was not bypassed.

Copied terminal result:

PASS actual package token write/create access to caller descriptor
PASS live denied desktop: genuine restricted token, read allowed
PASS live denied desktop: Windows AccessCheck denies write/create
PASS actual launcher encounters identical existing-deny DACL
PASS rejection before child creation: no launch receipt or sentinel
PASS exact-owned launcher process exited; both desktops removed
PASS owned negative window station and reference desktop removed
PASS token default DACL restored by Windows API and byte readback
PASS WinSta0 Default DACL and mandatory label unchanged
Negative token is restricted, NOT an AppContainer.
No separate-desktop isolation, ETW, or no-dialog claim.

Redacted executed-outcome receipt:

{
  "head": "15cd728cb8d3833c266e089e9aae3486dab28444",
  "sourceVersion": "1.0.0+15cd728cb8d3833c266e089e9aae3486dab28444",
  "actualAppContainer": true,
  "lowIntegrity": true,
  "user32Initialized": true,
  "assignedDesktopEqualsCaller": true,
  "realRestrictedToken": true,
  "liveDeniedDesktopWriteCreateDenied": true,
  "identicalDeniedDaclEncounteredByLauncher": true,
  "launcherRejectedBeforeChildCreation": true,
  "positiveExactProcessExited": true,
  "positiveDesktopRemoved": true,
  "deniedDesktopRemoved": true,
  "tokenDefaultDaclRestored": true,
  "ownedWindowStationRemoved": true,
  "winSta0DefaultDaclAndLabelUnchanged": true,
  "noDialogVerified": false
}
Executed input SHA256
Launcher 80895F5A7096C61EF6776AEF631FB2AD955F013E6E6E3B26A894FEDA59BE6E1B
Desktop-security policy 12B0CBB43A7D0AED6E0BF05DA118C1373DCFDD4F4CC5FC7807EE94B7662EA7A6
Harness executable 3266DD1CA4E58E570DE6D219720896ED4579256C7AC3753F605FF224FF1EA950
Harness assembly E61C5226D90BFAA7E05FE28158F9A97FE8257F1437BBBF4B082D667036D252D9
Native SDK runtime 56B152836698771FBE56D2AB8BE72F2F619031601DD2F00188B95C0FEC2A53DE
Native probe 5898FB8EE76C90759A78772C1253EB9DEBF5BF70F65ADF6BAA883D294FB5261F

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs or instructions
  • Tests or validation
  • Security hardening
  • Chore or infrastructure

Scope

  • Tray or WinUI UX
  • Windows node capability
  • Local MCP or winnode
  • Gateway, connection, or pairing
  • Setup or onboarding
  • Permissions, privacy, or security
  • Tests, CI, or docs

Required proof pools

  • windows-wsl-mxc: native Windows capacity is needed for the real token/desktop authorization boundary. The bounded current-head authority proof above ran; no claim that this alone completes the full WSL/MXC pool.

Validation

  • Exact head 15cd728c: .\scripts\validate-docs.ps1 PASS, 81 Markdown files and documentation-flow regression; .\scripts\validate-agent-skills.ps1 PASS, 12 skills / 21 Markdown files; git diff --check PASS.
  • Exact guest build: dotnet build .\tests\OpenClaw.DesktopHarness\OpenClaw.DesktopHarness.csproj -c Debug -m:1 --disable-build-servers -p:UseSharedCompilation=false --nologo --verbosity quiet PASS. The current native probe compiled with MSVC /O1 /MT /W4 and advapi32.lib: PASS.
  • Actual launcher invocation: scripts\Invoke-PrivateDesktop.ps1 with -NullSecurityNegativeControl -ConsoleProcess -WaitForExit, current harness and hash-bound native probe/runtime: PASS, AppContainer/Low/USER32, exit 0.
  • External authority fixture continuation used Invoke-AuthorityProof.ps1 -Repository <owned-exact-checkout> -HarnessExecutable <hash-bound-harness> -NativeRuntimeLibrary <hash-bound-runtime> -NativeProbeExecutable <hash-bound-probe> -OutputDirectory <owned-proof> -ExpectedHead 15cd728cb8d3833c266e089e9aae3486dab28444 -ResumePositive: PASS, existing-deny guard and teardown. It consumed the preserved positive receipt rather than rerunning the positive SDK case. Crabbox run_35ea07423c5f5d45388984dc85d7e78a, exit 0, nonexpired.
  • Hosted exact-head CI run 40438363447: GREEN, including CI Gate and UI tests. It was retriggered once by an authorized close/reopen after the preceding native test host crashed after 141 passes and 1 skip. The same crash symptom was verified in another PR run 39583645632; a shared root cause was not inferred. No dummy commit, assertion change or admin-permission bypass was used.
  • Unchanged-code prior fe5bdafe full build PASS, 395.665 seconds; native-free finalization checks 84 PASS. Its High Shared suite recorded 4664 passed / 2 failed / 8 nonexecuted; both failures passed exact focused current/main comparisons (2/2 each), so originals remain unreproduced, not demonstrated baseline failures. Queue sanity 2/2 PASS. These earlier results are not relabeled as fresh 15cd728c suite runs.

Failed external-fixture setup attempts were retained, not counted as passing security proof. Windows rejected an application-package restricting SID in CreateRestrictedToken with error 87; changing token-default DACL did not inject a desktop deny. The final fixture used the documented NULL-desktop inheritance from a newly owned window station. An unnecessary thread-desktop assignment failed with Windows 170 and was removed from the external fixture. No product-policy assertion, source or token restriction was relaxed to obtain a pass.

Real Behavior Proof

  • Environment tested: exclusive Hyper-V Windows normal guest, High interactive proof actor, SDK 10.0.402, PowerShell 7.6.7 and VS 18.10.4 with official app-local CRT; no host-native test execution. Lease cbx_87ef81f79ecc; no provider run URL returned.
  • PR head or commit tested: exact 15cd728cb8d3833c266e089e9aae3486dab28444, clean genuine checkout, informational version and executed binary hashes above.
  • Exact steps or command run: build current harness/probe; one actual launcher/SDK AppContainer positive; construct a live inherited-deny control on a new owned station; check actual restricted-token authorization; invoke actual launcher against matching denied DACL; verify no child creation and teardown.
  • Evidence after fix: screenshot, copied terminal output and redacted receipt above. Export recomputed and matched all frozen launcher, policy, fixture, proof-runner, harness, native-runtime and native-probe hashes.
  • Observed result: bounded authority-chain proof PASS. The negative is a restricted token, not an AppContainer; no execution-desktop isolation or no-dialog claim.
  • Screenshot or artifact links verified? (Yes/No/N/A) Yes: anonymous HTTP 200 with matching PNG bytes at a commit-pinned normal fork branch. Redacted local export SHA256 FC5754D806077B3C39B950ECA2C2D8513946F2466CFB51703BAB335FF45845FB; it is not represented as a public downloadable artifact.
  • Not verified or blocked: no current-head ETW trace, full SDK matrix, separate-desktop isolation, or no-dialog assertion. Earlier historical trace on 2ae4a900 reported 21 unattributed OBJECT_SHOW events with a separate decoder limitation and noDialogVerified=false; it is not current-head proof.

Security Impact

  • New permissions or capabilities? (Yes/No) Yes, missing package rights and a Low no-write-up label only on the newly owned test desktop.
  • Secrets or tokens handling changed? (Yes/No) No.
  • New or changed network calls? (Yes/No) No product network changes.
  • Command or tool execution surface changed? (Yes/No) Yes, test-harness prepared execution and validation, not a new Windows node command.
  • Data access scope changed? (Yes/No) No user-data access expansion.
  • If any answer is Yes, explain the risk and mitigation: preserve existing deny entries, owner/group/audit and caller-token restrictions; reject an existing write/create deny before child creation. Only a new exclusively owned desktop is eligible. The actual Windows authorization and launcher observations above are separate from synthetic descriptor fixtures. WinSta0 readback compares DACL and mandatory label; it does not independently verify every owner/group/audit field.

Compatibility and Migration

  • Backward compatible? (Yes/No) Yes. Ordinary fidelity runs keep their normal explicit build path when no expected harness hash is supplied.
  • Config or environment changes? (Yes/No) No product configuration changes. Native proof uses an explicitly authorized throwaway guest and task-owned artifacts.
  • Migration needed? (Yes/No) No.
  • If yes, list the exact upgrade steps: N/A.

Review Conversations

  • I replied to or resolved every bot review conversation addressed by this PR.
  • I left unresolved only conversations that still need maintainer judgment.

@clawsweeper

clawsweeper Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. labels Oct 20, 2026
@clawsweeper

clawsweeper Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex review: needs maintainer review before merge.

What this changes

Adds an owned private-desktop launcher and SDK startup harness that preserve desktop permissions, record diagnostics, and verify cleanup.

Example: SDK 1.0.0 starts an AppContainer on a newly created NULL-security test desktop.

  • Before: Missing package write/create rights and an implicit Medium integrity label can prevent USER32 initialization.
  • After: The owned desktop receives missing 0x82 package rights and a Low no-write-up label; an existing write/create deny rejects the launch before child creation.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) Useful validation tooling with direct native authority proof, green exact-head CI, and no identified blocking finding.
Proof confidence 🦞 diamond lobster (5/6) ✨ media proof bonus Sufficient (screenshot): At exact head 15cd728, the actual launcher and published SDK ran in an exclusive Hyper-V Windows guest: AppContainer/Low USER32 startup passed, a real restricted token failed write/create AccessCheck, the matching denied DACL caused launcher rejection before child creation, and owned resources were removed; the downloaded terminal screenshot was inspected directly.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: Developers cannot reliably validate sandbox startup when a task-owned private desktop lacks required USER32 access.
Reason: The change enables owned native validation without weakening product sandbox policy or introducing a user-facing preference.

Merge readiness

✅ Ready for maintainer review

Keep this PR open: it provides distinct private-desktop validation tooling absent from main, addresses the previous findings, and has no newly identified blocking defect.

Priority: P2
Reviewed head: 15cd728cb8d3833c266e089e9aae3486dab28444

Before merge

None.

Findings

None.

Tests

  • Missing end-to-end proof: The supplied current-head evidence covers bounded admission, rejection, and teardown, while explicitly leaving the full SDK matrix, ETW attribution, and no-dialog observation unverified.
Agent review details

How this fits together

Developer proof scripts create task-owned Windows desktops, invoke the existing MxcCommandRunner and published SDK, and produce startup, authorization, observation, and cleanup receipts.

flowchart TD
    A[Developer proof invocation] --> B[Owned desktop launcher]
    B --> C[Desktop security policy]
    C --> D[Desktop harness]
    D --> E[MxcCommandRunner and SDK]
    E --> F[Native startup probe]
    F --> G[Proof receipts and cleanup]
Loading

Technical review

Best possible solution:

Land the owned desktop admission and validation tooling when the author considers the draft ready, preserving the existing sandbox policy owner.

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

The descriptor handling explains the startup failure, and supplied native evidence exercises the repaired admission path; this read-only review did not run an independent baseline reproduction.

Is this the best way to solve the issue?

The repair belongs in the test-desktop creator: it preserves MxcCommandRunner, rejects existing denies before launch, and keeps token restrictions intact; the observer and recorder support distinct diagnostic and cleanup contracts.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against ed1444b0de69.

Provenance checked

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

Likely related people:

  • Scott Hanselman: Raw commit 6a7651e adds docs/ACCESSIBILITY.md:24 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 6a7651ed9649; files: docs/ACCESSIBILITY.md)

Review metrics

Metric Value Why it matters
Added scope 5,179 additions, 0 deletions 456 lines implement launcher/security support, 4,709 supply harness tooling and its documentation, and 14 extend accessibility guidance; native authorization, process cleanup, and observation are distinct validation boundaries.

Labels

Label changes:

No label changes.

Label justifications:

  • P2: Repairs a developer validation workflow with limited product blast radius.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • proof: sufficient: Contributor real behavior proof is sufficient.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (6 earlier review cycles)
  • reviewed 2026-10-20T22:42:44.598Z sha e37970a :: needs changes before merge. :: [P2] Port the probe to the current MXC execution owner | [P2] Reap the owned child when post-launch work fails
  • reviewed 2026-10-21T20:13:11.103Z sha a91649f :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-22T03:18:02.381Z sha a91649f :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-22T07:31:42.813Z sha a91649f :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-27T01:46:20.020Z sha fe5bdaf :: needs real behavior proof before merge. :: [P3] Describe observed SDK desktop identity without promising isolation
  • reviewed 2026-10-27T03:20:06.745Z sha 15cd728 :: needs maintainer review before merge. :: none

Reviewed October 26, 2026, 11:25 PM ET / October 27, 2026, 03:25 UTC (Revision 7).

Extract the independently reviewed reliability seam without the held native timeout consumer. No change to executor releases, package pins or sandbox enforcement.
Use caller prefixes with internally generated unadvertised desktop names instead of reusable exact names. Retain nonblocking launch ownership until teardown. Restore caller isolation environment existence and values on every path, including explicitly unset variables.

Add actual-child contender and environment readback, exact-name binding rejection, and real launch-failure cleanup checks. The four shipped-SDK USER32/PowerShell negative and positive controls and new ownership/environment regressions pass. No native serializer dependency, product policy change, existing desktop mutation or elevation.
UNVALIDATED handoff: initial SDK-port harness build passed with zero warnings/errors. Final waiting-child receipt fixture, runtime qualification, full build, Shared and private Tray suites remain blocked by sustained CPU admission failures. No product SDK pin or policy owner changed.
UNVALIDATED source checkpoint. Set and restore inherited quiet process error mode before native child initialization. Retain native-handle identity and explicit initialization failure status. Add a real DLL_PROCESS_ATTACH failure fixture and native ownership controls. Compilation passed before the final small native-helper adjustment; final rebuild and all runtime proof require resource admission and explicit Home confirmation. No further harness or failure fixture was executed after the hold.
UNVALIDATED accepted-P2 follow-up. Pin the timeout root handle and compare native creation FILETIME before Kill(true), then retain the bounded wait on the original native handle. Preserve root-only cleanup for other failures and successful nonblocking behavior. Add a native event-controlled root/descendant timeout regression with identity-bound exit and desktop cleanup checks. Parser, docs, skills and diff checks passed; new native fixture compilation and all runtime proof remain pending. No child execution before Home confirms the quiet fix.
@paulcam206

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed proof: sufficient Contributor real behavior proof is sufficient. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Oct 21, 2026
@paulcam206

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@paulcam206

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@paulcam206

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Oct 27, 2026
@paulcam206 paulcam206 closed this Oct 27, 2026
@paulcam206 paulcam206 reopened this Oct 27, 2026
@paulcam206

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed 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. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Oct 27, 2026
@paulcam206
paulcam206 marked this pull request as ready for review October 27, 2026 03:28
@shanselman
shanselman merged commit 70328c6 into openclaw:main Oct 30, 2026
61 of 64 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants