Skip to content

fix(security): block workspace env from overriding Windows system root paths [AI]#74458

Merged
drobison00 merged 7 commits intoopenclaw:mainfrom
mmaps:fix/fix-540
May 4, 2026
Merged

fix(security): block workspace env from overriding Windows system root paths [AI]#74458
drobison00 merged 7 commits intoopenclaw:mainfrom
mmaps:fix/fix-540

Conversation

@mmaps
Copy link
Copy Markdown
Contributor

@mmaps mmaps commented Apr 29, 2026

Summary

  • Problem: A workspace .env file could set SystemRoot or WINDIR, causing OpenClaw's Windows security-audit flow to resolve icacls.exe and whoami.exe from an attacker-controlled directory rather than C:\Windows\System32.
  • Why it matters: Users who open an untrusted repository and run openclaw security audit on Windows could silently execute attacker-supplied binaries.
  • What changed: (1) SYSTEMROOT and WINDIR (case-insensitive) are now blocked in BLOCKED_WORKSPACE_DOTENV_KEYS. (2) resolveWindowsSystemCommand() in windows-acl.ts now validates each env var through normalizeWindowsInstallRoot() before use, and falls back to the hardcoded C:\Windows default instead of a bare command name, eliminating PATH-hijacking exposure even when no env var is present. (3) createIcaclsResetCommand() now uses the fully resolved, validated path instead of the bare "icacls" string.
  • What did NOT change: ACL inspection logic, trust classification, principal resolution, and all non-Windows code paths are unchanged.

Change Type (select all)

  • Bug fix
  • Security hardening

Scope (select all touched areas)

  • Auth / tokens

Linked Issue/PR

  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: resolveWindowsSystemCommand() accepted SystemRoot/WINDIR from the environment without validating they pointed to absolute, non-relative, non-UNC Windows paths; workspace .env loading had no block on these keys.
  • Missing detection / guardrail: No path validation on Windows system root env vars; no entry in BLOCKED_WORKSPACE_DOTENV_KEYS for SYSTEMROOT/WINDIR.
  • Contributing context (if known): The same normalizeWindowsInstallRoot() validator already existed in src/infra/windows-install-roots.ts but was not applied in the ACL path.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
  • Target test or file: src/infra/dotenv.test.ts, src/security/windows-acl.test.ts
  • Scenario the test should lock in: Relative/invalid SystemRoot is rejected and falls back to the hardcoded safe default; workspace .env cannot inject SYSTEMROOT/WINDIR in any casing.
  • Why this is the smallest reliable guardrail: Tests exercise the exact code paths reachable by a malicious workspace .env without requiring a full Windows environment.
  • Existing test that already covers this (if any): None — new tests added.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

None. The security audit flow behavior is unchanged for correctly configured Windows systems. Only attacker-supplied relative or invalid SystemRoot/WINDIR values are now rejected.

Diagram (if applicable)

Before:
[workspace .env: SystemRoot=.\fake-root] -> resolveWindowsSystemCommand() -> .\fake-root\System32\icacls.exe (attacker binary)

After:
[workspace .env: SystemRoot=.\fake-root] -> BLOCKED at dotenv load
                                         -> normalizeWindowsInstallRoot() returns null -> fallback: C:\Windows\System32\icacls.exe

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? Yes
  • Data access scope changed? No
  • Risk + mitigation: icacls.exe/whoami.exe are now always resolved from a validated absolute path. Relative or invalid env vars are rejected before use; bare command names (PATH-dependent) are no longer used as fallback.

Repro + Verification

Environment

  • OS: Windows (logic; tests run cross-platform via path.win32)
  • Runtime/container: Node 22+
  • Model/provider: N/A
  • Integration/channel (if any): N/A

Steps

  1. Create a workspace .env with SystemRoot=.\fake-root.
  2. Place a malicious binary at fake-root\System32\icacls.exe.
  3. Run openclaw security audit.

Expected

  • The env var is blocked at .env load. Even if injected via other means, normalizeWindowsInstallRoot() rejects the relative path and falls back to C:\Windows\System32\icacls.exe.

Actual (before fix)

  • The attacker-controlled binary was executed.

Evidence

  • Failing test/log before + passing after

New unit tests in src/infra/dotenv.test.ts and src/security/windows-acl.test.ts cover:

  • All casing variants of systemroot/windir blocked from workspace .env
  • Relative SystemRoot rejected; safe default used
  • Valid WINDIR fallback when SystemRoot is invalid
  • createIcaclsResetCommand emits fully validated path

Human Verification (required)

  • Verified scenarios: Code-reviewed the full diff. Traced resolveWindowsSystemCommand() call paths for both inspectWindowsAcl and createIcaclsResetCommand. Confirmed normalizeWindowsInstallRoot() rejects relative, UNC, and root-only paths.
  • Edge cases checked: Mixed-case env keys (SystemRoot vs SYSTEMROOT), WINDIR fallback, env with no Windows root vars (falls back to C:\Windows), createIcaclsResetCommand bare-string regression.
  • What you did not verify: Live execution on a physical Windows machine.

AI-assisted: this PR was created with Claude Code.

Review Conversations

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

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Hardcoded C:\Windows fallback may not be correct on non-standard Windows installs.
    • Mitigation: This is the same default used in windows-install-roots.ts. Non-standard installs should already have SystemRoot set correctly; the validator accepts any valid absolute drive-rooted path.

@mmaps mmaps requested a review from a team as a code owner April 29, 2026 15:52
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR hardens the Windows security-audit path by (1) adding SYSTEMROOT and WINDIR to BLOCKED_WORKSPACE_DOTENV_KEYS so workspace .env files cannot supply attacker-controlled binary roots, and (2) routing resolveWindowsSystemCommand() through the existing normalizeWindowsInstallRoot() validator so relative, UNC, and root-only paths are rejected with a safe C:\Windows fallback instead of falling back to bare PATH-resolved command names. New unit tests cover all case variants of the blocked keys and the relevant inspectWindowsAcl/createIcaclsResetCommand scenarios.

Confidence Score: 5/5

This PR is safe to merge — it narrows attack surface without changing any non-Windows or ACL-inspection logic.

Changes are minimal and focused: two new set entries in the dotenv blocklist, a validated env-lookup array replacing the old bare-string fallback, and updated tests. The normalizeWindowsInstallRoot validator was already well-tested and the new call sites follow the same pattern used in windows-install-roots.ts. No logic paths for non-Windows code are touched.

No files require special attention.

Reviews (1): Last reviewed commit: "fix: address issue" | Re-trigger Greptile

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 29, 2026

Codex review: needs maintainer review before merge.

Summary
The PR validates Windows system-root resolution for icacls.exe/whoami.exe, moves SYSTEMROOT/WINDIR into host-env override policy artifacts, updates generated macOS policy output, adds regression tests, and adds a changelog entry.

Reproducibility: yes. from source inspection. Current main can be exercised through inspectWindowsAcl() and createIcaclsResetCommand() with a relative SystemRoot or empty env to observe attacker-controlled or bare command construction, though I did not run live Windows execution in this read-only review.

Next step before merge
This is a security-sensitive Windows command-execution hardening PR that already contains the focused implementation; the next action is maintainer/security review and exact-head CI, not an automated replacement fix.

Security
Cleared: The diff narrows a Windows command-execution surface and does not add dependencies, workflows, package scripts, downloads, lockfile changes, or secret-handling changes.

Review details

Best possible solution:

Land one maintainer-approved Windows hardening that keeps workspace dotenv and host-env override policy aligned, validates system roots through the shared install-root helper, resolves ACL audit/fix binaries to trusted System32 paths, and coordinates with the remaining reg.exe follow-up.

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

Yes, from source inspection. Current main can be exercised through inspectWindowsAcl() and createIcaclsResetCommand() with a relative SystemRoot or empty env to observe attacker-controlled or bare command construction, though I did not run live Windows execution in this read-only review.

Is this the best way to solve the issue?

Yes, directionally. Reusing getWindowsInstallRoots() and the existing install-root normalizer is the narrow maintainable fix for ACL helper resolution; the remaining decision is maintainer/security approval, CI completion, and coordination with the open reg.exe hardening PR.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/infra/host-env-security.test.ts src/infra/host-env-security.reported-baseline.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values

What I checked:

  • current_main_acl_resolution: On current main, resolveWindowsSystemCommand() reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and falls back to the bare command name when no root is set. (src/security/windows-acl.ts:119, 89db1e5440f5)
  • current_main_reset_command: On current main, createIcaclsResetCommand() returns command: "icacls", so the fix execution path remains PATH-dependent before this PR. (src/security/windows-acl.ts:400, 89db1e5440f5)
  • current_main_dotenv_partial_hardening: Current main already blocks SYSTEMROOT and WINDIR in the workspace dotenv blocklist from the related merged dotenv work, but that does not harden ACL helper resolution or the reset command. (src/infra/dotenv.ts:87, 89db1e5440f5)
  • existing_validator: normalizeWindowsInstallRoot() already rejects empty, relative, UNC, root-only, newline/NUL, and PATH-list-like Windows roots, which is the shared validation seam reused by the PR. (src/infra/windows-install-roots.ts:54, 89db1e5440f5)
  • pr_head_acl_hardening: At PR head, ACL helper resolution uses getWindowsInstallRoots(...).systemRoot, and createIcaclsResetCommand() returns the resolved icacls.exe path instead of a bare executable name. (src/security/windows-acl.ts:120, 3ea8682bdd71)
  • pr_head_policy_and_tests: At PR head, SYSTEMROOT and WINDIR are blocked override keys while still allowed as inherited host OS values, and tests assert those names are dangerous override vars plus ACL command fallback/validation cases. (src/infra/host-env-security-policy.json:237, 3ea8682bdd71)

Likely related people:

  • steipete: GitHub file history shows Peter Steinberger introduced the Windows ACL audit path and has recent maintenance in Windows ACL and infra helpers relevant to this security surface. (role: introduced behavior and recent maintainer; confidence: high; commits: ab73aceb27de, de0f54b54acc, 536e4f49bc39; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts, src/infra/windows-install-roots.ts)
  • optimol: Anmol Ahuja introduced the Windows install-root trust/override isolation helper that the PR reuses for validated system-root resolution. (role: adjacent owner; confidence: medium; commits: c40884d306e8; files: src/infra/windows-install-roots.ts)
  • pgondhi987: Pavan Kumar Gondhi has recent merged work on the host-env security policy and related workspace dotenv Windows system-path hardening in this cluster. (role: host-env policy contributor; confidence: medium; commits: 2d126fc62343, cba0a348dcdd, 42dfc36da50a; files: src/infra/host-env-security-policy.json, src/infra/dotenv.ts, src/infra/host-env-security.test.ts)
  • byungsker: Byungsker contributed prior merged Windows ACL /sid behavior that remains central to the audit helper path changed by this PR. (role: Windows ACL behavior contributor; confidence: medium; commits: 7735a0b85c72; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts)

Remaining risk / open question:

  • Exact-head CI was not complete at inspection time, including Windows-node coverage relevant to this patch.
  • No live Windows device smoke was available in this read-only review; the evidence is source and cross-platform unit-test coverage in the PR diff.
  • The neighboring fix: block SystemRoot/WINDIR in workspace .env and harden reg.exe path resolution [AI-assisted] #74454 reg.exe hardening thread remains open, so maintainers should coordinate the final Windows env-root hardening story before landing overlapping PRs.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 89db1e5440f5.

@mmaps
Copy link
Copy Markdown
Contributor Author

mmaps commented Apr 29, 2026

Addressed in bbaa0baf93e3b7f35094d13cf48c7de38b9b77cd.

Quoted comment from @clawsweeper:

Codex review: needs maintainer review before merge.

What this changes:

This PR blocks SYSTEMROOT/WINDIR from workspace .env, validates Windows system-root env values before resolving icacls.exe/whoami.exe, changes ACL reset execution to use a resolved system path, and adds dotenv/Windows ACL tests.

Maintainer follow-up before merge:

This is a security-sensitive command-execution hardening PR. The proposed patch appears narrow and reviewable, so the right next action is maintainer/security review and validation rather than an automated replacement fix PR.

Review details

Best possible solution:

Land a maintainer-approved hardening patch that blocks workspace .env Windows root injection, validates any Windows root env values through the existing install-root normalizer, resolves audit/fix helper execution to validated System32 paths, and keeps regression coverage for both dotenv loading and Windows ACL command construction.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge if maintainers proceed
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values

What I checked:

  • Current main accepts unvalidated Windows root env values for ACL helpers: On origin/main, resolveWindowsSystemCommand() reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and joins the value with System32; if no root is present it returns the bare command name. (src/security/windows-acl.ts:116, c1a42dce86cb)
  • Current main reset path still uses bare icacls: createIcaclsResetCommand() returns command: "icacls" on current main, so the fix path is still PATH-dependent before this PR. (src/security/windows-acl.ts:383, c1a42dce86cb)
  • Workspace dotenv blocklist lacks Windows root keys on main: The current BLOCKED_WORKSPACE_DOTENV_KEYS includes many credential/path override keys but does not include SYSTEMROOT or WINDIR. (src/infra/dotenv.ts:13, c1a42dce86cb)
  • Existing validator matches the proposed hardening direction: normalizeWindowsInstallRoot() already rejects empty, relative, UNC, root-only, NUL/newline, and PATH-list-like Windows root values, which is the validator the PR reuses. (src/infra/windows-install-roots.ts:54, c1a42dce86cb)
  • Security surface is the documented audit/fix path: The public CLI docs say openclaw security audit --fix tightens permissions and uses icacls resets on Windows, so the changed command resolution is on a user-facing security surface. Public docs: docs/cli/security.md. (docs/cli/security.md:66, c1a42dce86cb)
  • PR security review pass: The provided PR file list is limited to src/infra/dotenv.ts, src/infra/dotenv.test.ts, src/security/windows-acl.ts, and src/security/windows-acl.test.ts; it does not touch workflows, dependency manifests, lockfiles, package scripts, release metadata, downloaded artifacts, or secret-handling stores. (b3aa61663a6a)

Likely related people:

  • @steipete: Local blame and file history for src/security/windows-acl.ts, src/infra/dotenv.ts, and src/infra/windows-install-roots.ts point to Peter Steinberger on the commits that introduced the current main versions of these security/dotenv paths. (role: introduced behavior and recent maintainer; confidence: high; commits: e3a0c7615b8e, be8c24633aaa; files: src/security/windows-acl.ts, src/infra/dotenv.ts, src/infra/windows-install-roots.ts)

Remaining risk / open question:

  • No live Windows execution or CI results were available in the provided context; maintainer review should run the targeted tests and preferably a Windows smoke for the audit/fix path.
  • The patch leaves the human-readable remediation display as bare icacls; that is not an introduced regression in the diff, but maintainers may want to decide whether copy/paste guidance should also show the resolved system path.

Codex review notes: model gpt-5.5, reasoning high; reviewed against c1a42dce86cb.

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 29, 2026

Codex review: needs maintainer review before merge.

What this changes:

This PR blocks SYSTEMROOT/WINDIR from workspace .env, validates Windows system-root env values before resolving icacls.exe/whoami.exe, uses a resolved icacls.exe path for reset commands and display text, and adds dotenv/Windows ACL regression tests.

Maintainer follow-up before merge:

This is a security-sensitive command-execution hardening PR with overlapping open Windows dotenv hardening threads, so the next action is maintainer/security review and validation rather than an automated replacement fix PR.

Review details

Best possible solution:

Land one maintainer-approved hardening that blocks untrusted workspace dotenv Windows trust-root overrides, validates Windows root env values through the shared install-root normalizer for security audit/fix helper execution, resolves Windows helper binaries to validated System32 paths, and keeps regression coverage for both dotenv loading and ACL command construction.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge if maintainers proceed
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values

What I checked:

  • Current main ACL helper resolution is still env- and PATH-dependent: resolveWindowsSystemCommand() reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and returns a bare command name when no root exists; inspectWindowsAcl() and resolveCurrentUserSid() call it for icacls.exe and whoami.exe. (src/security/windows-acl.ts:116, 2dadc82cf453)
  • Current main reset path executes bare icacls: createIcaclsResetCommand() currently returns command: "icacls", so the fix path remains PATH-dependent before this PR. (src/security/windows-acl.ts:383, 2dadc82cf453)
  • Workspace dotenv blocklist lacks the Windows root keys on main: The current workspace dotenv blocklist uppercases keys before matching, but SYSTEMROOT and WINDIR are not present in BLOCKED_WORKSPACE_DOTENV_KEYS. (src/infra/dotenv.ts:13, 2dadc82cf453)
  • Existing validator supports the proposed hardening shape: normalizeWindowsInstallRoot() already rejects empty, relative, UNC, root-only, newline/NUL, and PATH-list-like values, and other Windows install-root code already uses case-insensitive env lookup plus the C:\Windows fallback. (src/infra/windows-install-roots.ts:54, 2dadc82cf453)
  • User-facing security surface uses Windows icacls resets: The CLI security docs state that openclaw security audit --fix tightens permissions and uses icacls resets on Windows, so the PR touches a documented security-audit/fix path. Public docs: docs/cli/security.md. (docs/cli/security.md:66, 2dadc82cf453)
  • PR diff is limited to source and tests for this hardening: The latest PR diff changes only src/infra/dotenv.ts, src/infra/dotenv.test.ts, src/security/windows-acl.ts, and src/security/windows-acl.test.ts; it does not add workflows, lockfile changes, package scripts, third-party actions, release metadata, downloaded artifacts, or new dependency sources. (bbaa0baf93e3)

Likely related people:

  • steipete: Local blame on the shallow checkout points the current windows-acl.ts, dotenv.ts, and windows-install-roots.ts snapshots to Peter Steinberger, and the GitHub timeline shows maintainer subscription/mentions on this security thread. (role: recent maintainer and security/dotenv path owner; confidence: high; commits: b7db63751b99, de0f54b54acc; files: src/security/windows-acl.ts, src/infra/dotenv.ts, src/infra/windows-install-roots.ts)
  • optimol: GitHub commit history for src/infra/windows-install-roots.ts shows c40884d306e8 added the Windows install-root trust/override isolation work that this PR reuses through normalizeWindowsInstallRoot(). (role: introduced adjacent Windows install-root trust helper; confidence: medium; commits: c40884d306e8; files: src/infra/windows-install-roots.ts)
  • byungsker: GitHub file history for src/security/windows-acl.ts shows prior merged Windows ACL audit work in commit 7735a0b85c72, including icacls /sid behavior that remains central to this path. (role: Windows ACL behavior contributor; confidence: medium; commits: 7735a0b85c72; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts)
  • pgondhi987: Recent src/infra/dotenv.ts history includes merged workspace dotenv hardening in ccb3af556fcb, and the related open fix(infra): block Windows system path env vars from workspace .env injection #74456 thread covers overlapping Windows dotenv hardening. (role: recent dotenv hardening contributor and adjacent PR author; confidence: medium; commits: ccb3af556fcb; files: src/infra/dotenv.ts, src/infra/dotenv.test.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 2dadc82cf453.

@mmaps
Copy link
Copy Markdown
Contributor Author

mmaps commented Apr 29, 2026

Addressed in 49d4bf4007b8205296c2e04c443c5b26549c278d.

Quoted comment from @clawsweeper:

Codex review: needs maintainer review before merge.

What this changes:

This PR blocks SYSTEMROOT/WINDIR from workspace .env, validates Windows system-root env values before resolving icacls.exe/whoami.exe, uses a resolved icacls.exe path for reset commands and display text, and adds dotenv/Windows ACL regression tests.

Maintainer follow-up before merge:

This is a security-sensitive command-execution hardening PR with overlapping open Windows dotenv hardening threads, so the next action is maintainer/security review and validation rather than an automated replacement fix PR.

Review details

Best possible solution:

Land one maintainer-approved hardening that blocks untrusted workspace dotenv Windows trust-root overrides, validates Windows root env values through the shared install-root normalizer for security audit/fix helper execution, resolves Windows helper binaries to validated System32 paths, and keeps regression coverage for both dotenv loading and ACL command construction.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge if maintainers proceed
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values

What I checked:

  • Current main ACL helper resolution is still env- and PATH-dependent: resolveWindowsSystemCommand() reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and returns a bare command name when no root exists; inspectWindowsAcl() and resolveCurrentUserSid() call it for icacls.exe and whoami.exe. (src/security/windows-acl.ts:116, 2dadc82cf453)
  • Current main reset path executes bare icacls: createIcaclsResetCommand() currently returns command: "icacls", so the fix path remains PATH-dependent before this PR. (src/security/windows-acl.ts:383, 2dadc82cf453)
  • Workspace dotenv blocklist lacks the Windows root keys on main: The current workspace dotenv blocklist uppercases keys before matching, but SYSTEMROOT and WINDIR are not present in BLOCKED_WORKSPACE_DOTENV_KEYS. (src/infra/dotenv.ts:13, 2dadc82cf453)
  • Existing validator supports the proposed hardening shape: normalizeWindowsInstallRoot() already rejects empty, relative, UNC, root-only, newline/NUL, and PATH-list-like values, and other Windows install-root code already uses case-insensitive env lookup plus the C:\Windows fallback. (src/infra/windows-install-roots.ts:54, 2dadc82cf453)
  • User-facing security surface uses Windows icacls resets: The CLI security docs state that openclaw security audit --fix tightens permissions and uses icacls resets on Windows, so the PR touches a documented security-audit/fix path. Public docs: docs/cli/security.md. (docs/cli/security.md:66, 2dadc82cf453)
  • PR diff is limited to source and tests for this hardening: The latest PR diff changes only src/infra/dotenv.ts, src/infra/dotenv.test.ts, src/security/windows-acl.ts, and src/security/windows-acl.test.ts; it does not add workflows, lockfile changes, package scripts, third-party actions, release metadata, downloaded artifacts, or new dependency sources. (bbaa0baf93e3)

Likely related people:

  • steipete: Local blame on the shallow checkout points the current windows-acl.ts, dotenv.ts, and windows-install-roots.ts snapshots to Peter Steinberger, and the GitHub timeline shows maintainer subscription/mentions on this security thread. (role: recent maintainer and security/dotenv path owner; confidence: high; commits: b7db63751b99, de0f54b54acc; files: src/security/windows-acl.ts, src/infra/dotenv.ts, src/infra/windows-install-roots.ts)
  • optimol: GitHub commit history for src/infra/windows-install-roots.ts shows c40884d306e8 added the Windows install-root trust/override isolation work that this PR reuses through normalizeWindowsInstallRoot(). (role: introduced adjacent Windows install-root trust helper; confidence: medium; commits: c40884d306e8; files: src/infra/windows-install-roots.ts)
  • byungsker: GitHub file history for src/security/windows-acl.ts shows prior merged Windows ACL audit work in commit 7735a0b85c72, including icacls /sid behavior that remains central to this path. (role: Windows ACL behavior contributor; confidence: medium; commits: 7735a0b85c72; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts)
  • pgondhi987: Recent src/infra/dotenv.ts history includes merged workspace dotenv hardening in ccb3af556fcb, and the related open fix(infra): block Windows system path env vars from workspace .env injection #74456 thread covers overlapping Windows dotenv hardening. (role: recent dotenv hardening contributor and adjacent PR author; confidence: medium; commits: ccb3af556fcb; files: src/infra/dotenv.ts, src/infra/dotenv.test.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 2dadc82cf453.

@openclaw-barnacle openclaw-barnacle Bot added the app: macos App: macos label Apr 29, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 29, 2026

Codex review: needs maintainer review before merge.

What this changes:

This PR marks SYSTEMROOT and WINDIR as blocked override variables in host env policy, updates generated/baseline policy artifacts and tests, exports the shared Windows system-root default, and changes Windows ACL audit/reset command construction to use validated System32 executable paths.

Maintainer follow-up before merge:

This is an open, security-sensitive command-execution hardening PR with overlapping Windows env-policy PRs; the next step is maintainer/security review, CI completion, and possible consolidation, not an automated replacement fix.

Review details

Best possible solution:

Land one maintainer-approved hardening that blocks untrusted workspace dotenv Windows root overrides through the shared host env policy, validates Windows system roots before resolving audit/fix helper binaries, uses validated System32 paths for execution, keeps generated policy artifacts in sync, and coordinates the overlapping Windows env hardening PRs into a coherent final state.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/infra/host-env-security.test.ts src/infra/host-env-security.reported-baseline.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values and verify icacls.exe/whoami.exe resolution

What I checked:

  • Current main still resolves ACL helpers from unvalidated env roots: On current main, resolveWindowsSystemCommand reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and otherwise returns the bare command name, so the audit path remains env- and PATH-dependent before this PR. (src/security/windows-acl.ts:116, 0519107bd3e2)
  • Current main reset execution still uses bare icacls: createIcaclsResetCommand currently returns command: "icacls" while only the display string is formatted separately, so the fix path is still PATH-dependent on main. (src/security/windows-acl.ts:383, 0519107bd3e2)
  • Current main workspace dotenv/host env policy does not block Windows root keys: The current workspace dotenv blocklist and host env override policy do not include SYSTEMROOT or WINDIR; the PR moves those keys through the host-env-security policy path so workspace dotenv loading blocks them via shouldBlockWorkspaceRuntimeDotEnvKey. (src/infra/dotenv.ts:13, 0519107bd3e2)
  • Existing validator supports the proposed fix shape: normalizeWindowsInstallRoot already rejects empty, relative, UNC, root-only, newline/NUL, and PATH-list-like Windows install-root values; the PR reuses that validator for ACL helper resolution. (src/infra/windows-install-roots.ts:54, 0519107bd3e2)
  • Security audit/fix surface is user-facing: The CLI security docs say openclaw security audit --fix tightens permissions and uses icacls resets on Windows, so the changed command resolution is on a documented security remediation path. Public docs: docs/cli/security.md. (docs/cli/security.md:66, 0519107bd3e2)
  • Latest PR diff is scoped to env policy, generated macOS policy, Windows install-root sharing, ACL code, and tests: The latest head 49d4bf4 changes nine source/test/generated policy files and does not touch workflows, dependency manifests, lockfiles, package scripts, release metadata, downloaded artifacts, or third-party action refs. (49d4bf4007b8)

Likely related people:

  • steipete: GitHub file history shows Peter Steinberger introduced the Windows ACL audit path in ab73ace and recently maintained Windows ACL tests in de0f54b; local blame on the current shallow tip also points these central files through recent maintainer work. (role: introduced behavior and recent maintainer; confidence: high; commits: ab73aceb27de, de0f54b54acc, 0519107bd3e2; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts, src/infra/dotenv.ts)
  • optimol: GitHub file history shows c40884d added the Windows install-root trust and override isolation helper that this PR reuses through normalizeWindowsInstallRoot. (role: adjacent owner; confidence: medium; commits: c40884d306e8; files: src/infra/windows-install-roots.ts)
  • pgondhi987: GitHub history shows prior merged host env security policy expansion work, and a related open PR in the provided context covers the same Windows root/env family for taskkill.exe. (role: host env policy contributor; confidence: medium; commits: 2d126fc62343, ccb3af556fcb; files: src/infra/host-env-security-policy.json, src/infra/dotenv.ts)
  • eleqtrizit: GitHub file history for dotenv and host env policy includes several merged changes by eleqtrizit around workspace dotenv namespace and inherited host exec env filtering. (role: adjacent host env/dotenv maintainer; confidence: medium; commits: 018494fa3ebb, fa82193c7273, 423a14e2bec6; files: src/infra/dotenv.ts, src/infra/host-env-security-policy.json, src/infra/host-env-security.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 0519107bd3e2.

@mmaps
Copy link
Copy Markdown
Contributor Author

mmaps commented Apr 29, 2026

Addressed in 539a4e584c9dbb32b15b1a72bbfe3743cd34cebc.

Quoted comment from @clawsweeper:

Codex review: needs maintainer review before merge.

What this changes:

This PR marks SYSTEMROOT and WINDIR as blocked override variables in host env policy, updates generated/baseline policy artifacts and tests, exports the shared Windows system-root default, and changes Windows ACL audit/reset command construction to use validated System32 executable paths.

Maintainer follow-up before merge:

This is an open, security-sensitive command-execution hardening PR with overlapping Windows env-policy PRs; the next step is maintainer/security review, CI completion, and possible consolidation, not an automated replacement fix.

Review details

Best possible solution:

Land one maintainer-approved hardening that blocks untrusted workspace dotenv Windows root overrides through the shared host env policy, validates Windows system roots before resolving audit/fix helper binaries, uses validated System32 paths for execution, keeps generated policy artifacts in sync, and coordinates the overlapping Windows env hardening PRs into a coherent final state.

Acceptance criteria:

  • pnpm test src/infra/dotenv.test.ts src/infra/host-env-security.test.ts src/infra/host-env-security.reported-baseline.test.ts src/security/windows-acl.test.ts
  • pnpm check:changed in Testbox before merge
  • Optional Windows smoke: run openclaw security audit and openclaw security audit --fix with controlled SystemRoot/WINDIR values and verify icacls.exe/whoami.exe resolution

What I checked:

  • Current main still resolves ACL helpers from unvalidated env roots: On current main, resolveWindowsSystemCommand reads SystemRoot/SYSTEMROOT/windir/WINDIR directly and otherwise returns the bare command name, so the audit path remains env- and PATH-dependent before this PR. (src/security/windows-acl.ts:116, 0519107bd3e2)
  • Current main reset execution still uses bare icacls: createIcaclsResetCommand currently returns command: "icacls" while only the display string is formatted separately, so the fix path is still PATH-dependent on main. (src/security/windows-acl.ts:383, 0519107bd3e2)
  • Current main workspace dotenv/host env policy does not block Windows root keys: The current workspace dotenv blocklist and host env override policy do not include SYSTEMROOT or WINDIR; the PR moves those keys through the host-env-security policy path so workspace dotenv loading blocks them via shouldBlockWorkspaceRuntimeDotEnvKey. (src/infra/dotenv.ts:13, 0519107bd3e2)
  • Existing validator supports the proposed fix shape: normalizeWindowsInstallRoot already rejects empty, relative, UNC, root-only, newline/NUL, and PATH-list-like Windows install-root values; the PR reuses that validator for ACL helper resolution. (src/infra/windows-install-roots.ts:54, 0519107bd3e2)
  • Security audit/fix surface is user-facing: The CLI security docs say openclaw security audit --fix tightens permissions and uses icacls resets on Windows, so the changed command resolution is on a documented security remediation path. Public docs: docs/cli/security.md. (docs/cli/security.md:66, 0519107bd3e2)
  • Latest PR diff is scoped to env policy, generated macOS policy, Windows install-root sharing, ACL code, and tests: The latest head 49d4bf4 changes nine source/test/generated policy files and does not touch workflows, dependency manifests, lockfiles, package scripts, release metadata, downloaded artifacts, or third-party action refs. (49d4bf4007b8)

Likely related people:

  • steipete: GitHub file history shows Peter Steinberger introduced the Windows ACL audit path in ab73ace and recently maintained Windows ACL tests in de0f54b; local blame on the current shallow tip also points these central files through recent maintainer work. (role: introduced behavior and recent maintainer; confidence: high; commits: ab73aceb27de, de0f54b54acc, 0519107bd3e2; files: src/security/windows-acl.ts, src/security/windows-acl.test.ts, src/infra/dotenv.ts)
  • optimol: GitHub file history shows c40884d added the Windows install-root trust and override isolation helper that this PR reuses through normalizeWindowsInstallRoot. (role: adjacent owner; confidence: medium; commits: c40884d306e8; files: src/infra/windows-install-roots.ts)
  • pgondhi987: GitHub history shows prior merged host env security policy expansion work, and a related open PR in the provided context covers the same Windows root/env family for taskkill.exe. (role: host env policy contributor; confidence: medium; commits: 2d126fc62343, ccb3af556fcb; files: src/infra/host-env-security-policy.json, src/infra/dotenv.ts)
  • eleqtrizit: GitHub file history for dotenv and host env policy includes several merged changes by eleqtrizit around workspace dotenv namespace and inherited host exec env filtering. (role: adjacent host env/dotenv maintainer; confidence: medium; commits: 018494fa3ebb, fa82193c7273, 423a14e2bec6; files: src/infra/dotenv.ts, src/infra/host-env-security-policy.json, src/infra/host-env-security.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 0519107bd3e2.

@drobison00 drobison00 merged commit c1da0dd into openclaw:main May 4, 2026
108 checks passed
arieldiego73 pushed a commit to arieldiego73/openclaw that referenced this pull request May 5, 2026
…t paths [AI] (openclaw#74458)

* fix: address issue

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* changelog: PR openclaw#74458

---------

Co-authored-by: Devin Robison <[email protected]>
cbeltrao added a commit to stationzeroai/openclaw-updated-from-original-repository that referenced this pull request May 5, 2026
* feat(models): list auth profiles

* fix(gateway): clarify systemd service scope

* fix(types): wire plugin package metadata

* test(agents): update model auth fixture shape

* test: harden plugin and UI isolation checks

* docs(changelog): credit recent plugin fixes

* fix: proxy direct APNs HTTP2 sessions (#74905)

Summary:
- This PR routes direct APNs HTTP/2 sends through an APNs allowlisted managed-proxy CONNECT wrapper, adds APNs proxy validation/docs/guardrails, and expands regression and live-test coverage.
- Reproducibility: yes. source-reproducible: current main `sendApnsRequest()` still uses raw `http2.connect(au ... nly covers HTTP/global-agent/Undici hooks. I did not run a live APNs reproduction in this read-only review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: test: guard raw HTTP2 APNs connections
- PR branch already contained follow-up commit before automerge: test: guard raw HTTP2 with OpenGrep
- PR branch already contained follow-up commit before automerge: lint: ban raw HTTP2 imports
- PR branch already contained follow-up commit before automerge: fix: use managed proxy state for APNs
- PR branch already contained follow-up commit before automerge: test: exercise APNs active proxy state
- PR branch already contained follow-up commit before automerge: fix: reject conflicting managed proxy activation

Validation:
- ClawSweeper review passed for head dab7c86a7595a01b09c32395578e7c26a03f938d.
- Required merge gates passed before the squash merge.

Prepared head SHA: dab7c86a7595a01b09c32395578e7c26a03f938d
Review: https://github.com/openclaw/openclaw/pull/74905#issuecomment-4350181159

Co-authored-by: jesse-merhi <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* test: stabilize full crabbox sweep

* fix: refresh stale codex auth profile routing

Summary:
- Promotes fresh Codex OAuth relogin profiles ahead of stale per-agent auth order entries.
- Repairs invalidated per-agent Codex order and session overrides toward healthy relogin profiles.
- Adds focused regression coverage for auth order, invalidated profile repair, and session override re-resolution.

Verification:
- pnpm test src/agents/auth-profiles/profiles.test.ts src/agents/auth-profiles.ensureauthprofilestore.test.ts src/agents/auth-profiles/session-override.test.ts src/commands/models/auth.test.ts -- --reporter=verbose
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/agents/auth-profiles.ensureauthprofilestore.test.ts src/agents/auth-profiles/persisted.ts src/agents/auth-profiles/profiles.test.ts src/agents/auth-profiles/profiles.ts src/agents/auth-profiles/session-override.test.ts src/agents/auth-profiles/session-override.ts src/commands/models/auth.test.ts src/commands/models/auth.ts
- git diff --check origin/main...HEAD
- pnpm check:changed via Blacksmith Testbox tbx_01kqscwvkywnt72qx1t8a07tp8
- GitHub CI on 1a6f93a3723236efb8132dec3f2bc8be505c7364, with checks-node-core-runtime-infra-state rerun passing after an unrelated stale-lock timing failure

* test(release): leave Windows updater timeout headroom

* Control UI explicit action feedback

Add explicit Control UI feedback for repeated actions: session switches now announce through the chat controls live-status path and flash the active session selector, config actions show inline busy state, and session list empty states distinguish filtered results with a Show all reset. Also refresh generated Control UI locale metadata and fallback markers.

* chore(ui): refresh zh-CN control ui locale

* chore(ui): refresh de control ui locale

* chore(ui): refresh zh-TW control ui locale

* chore(ui): refresh pt-BR control ui locale

* chore(ui): refresh es control ui locale

* chore(ui): refresh ja-JP control ui locale

* chore(ui): refresh ko control ui locale

* chore(ui): refresh fr control ui locale

* chore(ui): refresh ar control ui locale

* chore(ui): refresh tr control ui locale

* chore(ui): refresh it control ui locale

* chore(ui): refresh uk control ui locale

* chore(ui): refresh id control ui locale

* chore(ui): refresh pl control ui locale

* chore(ui): refresh vi control ui locale

* chore(ui): refresh th control ui locale

* chore(ui): refresh nl control ui locale

* chore(ui): refresh fa control ui locale

* test: repair current main checks

* fix(tui): abort run during pre-event waiting gap (#77199)

* fix(tui): abort run during pre-event waiting gap

Track the runId returned from chat.send so pressing Esc while `activeChatRunId` is still null aborts the in-flight run instead of repeatedly printing "no active run". Identified in #1296.

* fix(tui): drop redundant comment on pendingChatRunId set

* docs(changelog): restore 2026.5.3 release notes

* fix(tui): preserve code spans, code blocks, and dotted/hyphenated identifiers from long-token sanitizer (#77335)

The display sanitizer's long-token chunker (`\S{33,}` -> 32-char chunks
joined by spaces) was injecting literal spaces inside inline code spans,
fenced code blocks, and bare identifiers it didn't recognize. Tokens like
`requireConfirmationForMutatingActions`, `ubuntu-budgie-desktop-environment`,
and `binary_sensor.sense_energy_monitor_power` rendered with mid-word
spaces, contaminating copy/paste of package names, entity IDs, and shell
line-continuations.

Fix:

- Make sanitizer code-aware: split text into fenced/inline-code segments
  and prose, and only run the chunker on prose segments. Code regions
  pass through verbatim.
- Widen `isCopySensitiveToken` to use the punctuation-stripped candidate
  for all classification, and accept any `FILE_LIKE_RE` token that
  contains `_`, `-`, or `.` (covers package names, dotted IDs, kebab
  flags). Picks up the goals of #69340 and #39565.
- Skip chunking for symbol-only runs (box-drawing rows, dashes, equals)
  so table borders aren't corrupted.
- Preserve the original goal of narrow-terminal protection: long
  unidentifiable prose tokens (e.g. accidental base64 dumps) are still
  chunked so they don't blow out terminal layout.

Security ordering preserved: ANSI strip / control-char strip / binary
redaction still run on the whole string before segmentation, so code
regions cannot smuggle escapes, control characters, or binary garbage
past the sanitizer.

16 new regression tests cover: camelCase config keys in inline code,
hyphenated package names (bare and in code), dotted entity IDs (bare
and in code), backtick and tilde fenced blocks, base64-like blobs in
code, prose-token chunking unchanged, prose-around-code mixed content,
box-drawing horizontal rules, multi-line shell `\\` continuations,
plus three explicit security-ordering tests asserting ANSI/control/
binary stripping still runs inside code segments.

Fixes #48432, #39505.
Supersedes #69340, #39565 (carries forward both ideas in a more
general fix). Carries forward the code-fence-aware approach from the
closed #48445.

* fix(telegram): clean up tool-only previews

* [plugin sdk] Harden finalize retry and run context cleanup (#75600)

Merged via squash.

Prepared head SHA: ec58a6212b0aa239bf23d339d825eeff0777b611
Co-authored-by: 100yenadmin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* feat(cron): surface run diagnostics in status (#75928)

* feat(cron): surface run diagnostics in status

* docs: add cron diagnostics changelog

* fix(cron): preserve latest run diagnostics

* test(cron): update diagnostics regression deps

* fix(memory): prevent memory-hit starvation in corpus=all by capping per-corpus results (#77337) (#77356)

Summary:
- The PR adds balanced, backfilled all-corpus result merging for `memory_search` and `wiki_search`, regression tests, and a changelog entry for #77337.
- Reproducibility: yes. Current main is source-reproducible: both affected paths fetch both corpora for `corpus=all`, raw-sort wiki integer scores against memory similarity scores, and slice to `maxResults`.

Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Included post-review commit in the final squash: fix(memory): prevent all-corpus memory hit starvation

Validation:
- ClawSweeper review passed for head a5b4f6a93210e748c40e64160848dac5c5fa94f1.
- Required merge gates passed before the squash merge.

Prepared head SHA: a5b4f6a93210e748c40e64160848dac5c5fa94f1
Review: https://github.com/openclaw/openclaw/pull/77356#issuecomment-4371767658

Co-authored-by: HCL <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* fix(qqbot): keep private commands off framework surface [AI] (#77212)

* fix: keep private qqbot commands off framework surface

* addressing codex review

* docs: add changelog entry for PR merge

* [plugin sdk] Project session extension slots (#75609)

Merged via squash.

Prepared head SHA: d9b670a8676d7ecc638568c9713a103dc58a2868
Co-authored-by: 100yenadmin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* fix #77296: [Bug]: Plugin manifest `skills` field not published to agent skill discovery paths (#77328)

Summary:
- The PR publishes enabled plugin-declared skill directories into a generated `~/.openclaw/plugin-skills` syml ... plugin-skill precedence, cleans stale generated links, adds regression coverage, and updates the changelog.
- Reproducibility: yes. source-based. Current main resolves plugin-declared skill directories for prompt loadi ... ble generated discovery path, and the linked issue provides a concrete ENOENT path for a plugin `SKILL.md`.

Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Included post-review commit in the final squash: fix: resolve issue #77296
- Included post-review commit in the final squash: fix: publish plugin manifest skills for agent discovery
- Included post-review commit in the final squash: fix(clawsweeper): address review for automerge-openclaw-openclaw-7732…

Validation:
- ClawSweeper review passed for head 0f52865ee3a9b268bf33ab012a787b2b32fdd050.
- Required merge gates passed before the squash merge.

Prepared head SHA: 0f52865ee3a9b268bf33ab012a787b2b32fdd050
Review: https://github.com/openclaw/openclaw/pull/77328#issuecomment-4371415857

Co-authored-by: zhang-guiping <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* fix(security): block workspace env from overriding Windows system root paths [AI] (#74458)

* fix: address issue

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* changelog: PR #74458

---------

Co-authored-by: Devin Robison <[email protected]>

* test(acpx): cover Windows extension test paths

* test(bluebubbles): accept native contact database paths

* test(diffs): use native viewer asset file URLs

* test(discord): accept native voice temp paths

* test(feishu): cover native Windows webhook and workspace paths

* test(feishu): accept native oversized body resets

* test(matrix): cover native Windows file semantics

* test(memory): cover native Windows paths and locks

* test(telegram): accept native Windows session file paths

* test(whatsapp): accept native Windows auth paths

* test(openshell): accept native symlink targets

* test(anthropic-vertex): accept native ADC home paths

* fix(qa-channel): settle aborted bus polls

* test(qa-lab): accept native Windows paths

* fix(device-pair): require pairing scope for pair command [AI] (#76377)

* fix: restrict device pairing command access

* addressing review-skill

* addressing review-skill

* addressing codex review

* address codex review feedback

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* docs: add changelog entry for PR merge

* Gate zalouser startup name matching [AI] (#77411)

* fix: gate zalouser startup name matching

* addressing codex review

* docs: add changelog entry for PR merge

* fix: block SystemRoot/WINDIR in workspace .env and harden reg.exe path resolution [AI-assisted] (#74454)

* fix: address issue

* fix: address PR review feedback

* Add changelog entry for PR #74454

---------

Co-authored-by: Devin Robison <[email protected]>

* Feat/main session durable delivery pr (#75280)

* feat: generalize pending-final-delivery for subagents and main session

(cherry picked from commit 677fcbfaf87c8cd6de8b5bd02099b29b7d49e916)

* feat(agents): implement Phase 2 durable final delivery for main sessions

(cherry picked from commit b4e39f0ddf6dbd3f0d3b9226df8e714ad722f751)

* fix(agents): narrow heartbeat deferral to pending final delivery

* fix(agents): clear final delivery after dispatch

* fix(agents): gate durable delivery retry capture

---------

Co-authored-by: Mert Basar <[email protected]>

* fix(gateway): clamp unbound websocket auth scopes [AI] (#77413)

* fix: clamp unapproved trusted proxy websocket scopes

* addressing claude review

* addressing claude review

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge

* fix(gateway): add safe restart coordinator (#76923)

Add a safe restart coordinator that preflights active Gateway work before restart.

- expose gateway.restart.preflight and gateway.restart.request RPC methods
- add explicit openclaw gateway restart --safe / openclaw daemon restart --safe path
- narrow restart blockers to running non-ended tasks so queued records no longer block indefinitely
- keep existing restart behavior unchanged; --force remains the immediate override

Co-authored-by: NikolaFC <[email protected]>
Co-authored-by: galiniliev <[email protected]>

* fix: pass claude cli thinking effort (#77410)

Summary:
- Adds a plugin-owned CLI backend argument rewrite hook and wires Anthropic `claude-cli` to translate non-off `/think` levels into Claude Code `--effort`, with docs, changelog, API baseline, and tests.
- Reproducibility: yes. Current main has a high-confidence source reproduction: choose `claude-cli`, set a non ... builds argv from backend args that contain no `--effort` even though `thinkLevel` exists on the run params.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head be17754009e5651ec9df6472f46fbffdfe3346e7.
- Required merge gates passed before the squash merge.

Prepared head SHA: be17754009e5651ec9df6472f46fbffdfe3346e7
Review: https://github.com/openclaw/openclaw/pull/77410#issuecomment-4372812685

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

* test(release): skip restart in package upgrade lane

* fix(plugins): reserve pending delivery session slots

* chore: better explicit message on whatsapp

* chore: ignore crabbox artifacts

* fix(plugins): trust catalog package installs

* docs(plugins): explain catalog install trust

* fix(active-memory): skip colon-containing session-store channels to prevent crash with QQ c2c agent IDs (#77402)

Summary:
- The PR filters colon-containing store-derived Active Memory channel values before embedded recall resolution, adds a QQ c2c regression test, and records the user-facing changelog entry.
- Reproducibility: yes. Source inspection on current main shows a stored colon-containing `lastChannel` or `ch ... come the strong embedded recall channel, and the downstream bundled-plugin directory validator rejects `:`.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fixup! fix(active-memory): add changelog contributor credit (clawswee…
- PR branch already contained follow-up commit before automerge: fix(active-memory): skip colon-containing session-store channels

Validation:
- ClawSweeper review passed for head 4bf00dd6acfc95d861779ec1fdd1ae36cab93797.
- Required merge gates passed before the squash merge.

Prepared head SHA: 4bf00dd6acfc95d861779ec1fdd1ae36cab93797
Review: https://github.com/openclaw/openclaw/pull/77402#issuecomment-4372618783

Co-authored-by: HCL <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* fix(qqbot): preserve framework command authorization (#77453)

* fix(qqbot): preserve framework command authorization

* Add changelog entry for PR #77453

* docs(changelog): credit @NikolaFC and @MertBasar0 for gateway and main-session fixes

#76923 (Satoshi F. / @NikolaFC) added user-facing `gateway.restart.safe`
preflight alignment and #75280 (Mert Başar / @MertBasar0) added
user-facing main-session pending-delivery marker preservation, but both
entries landed without contributor attribution. Add the merging PR refs
and credit the human contributors per CLAUDE.md changelog-attribution
rules.

* Use trusted Windows browser helper root (#77469)

* fix(agents): refresh deferred subagent delivery text

* fix(doctor): restore group config drift migrations (#77465)

* docs(changelog): credit group config migration fix

Credit @scoootscooob for #77465.

* ci: gate slack live qa credentials

* fix(process): kill Windows command trees on timeout

(cherry picked from commit 9cc3ae100b846437dd3dcbcfaf20b242d9f6f6a2)

* test(release): recover known Windows packaged upgrade timeout

(cherry picked from commit 8f7399e9e9decbb6e2125278a7ffb6327e9f0088)

* test(release): match versioned Windows upgrade tarballs

(cherry picked from commit b70dbe32d0311808e95448e0f78dee8931e09664)

* ci(release): fix ClawHub runtime preflight command

(cherry picked from commit 954b25e129f3d42a69d495a250c0f6c87bcf47f2)

* fix codex thread continuity

* docs: credit Codex context PR (#76824)

* Harden update environment path resolution (#77470)

* Harden update environment path resolution

* docs(changelog): credit windows update env path hardening

Adds the user-facing Unreleased Fixes entry for the workspace LOCALAPPDATA
blocklist + portable Git path-prepend hardening change in this PR.

* Fix Active Memory memory-only recall latency (#75200)

Summary:
- The PR adds a bounded latest-message search-query section to Active Memory recall prompts, regression coverage for metadata stripping, a changelog entry, and pending-final-delivery session slot reservations.
- Reproducibility: yes. for a source-level reproduction path: an eligible interactive turn reaches Active Memo ... om current releases, but I did not run a live gateway/provider reproduction under the read-only constraint.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(plugins): reserve final delivery session slots

Validation:
- ClawSweeper review passed for head 24bf408e75d87081c8736f1df7fd06bc3b4f887e.
- Required merge gates passed before the squash merge.

Prepared head SHA: 24bf408e75d87081c8736f1df7fd06bc3b4f887e
Review: https://github.com/openclaw/openclaw/pull/75200#issuecomment-4354978044

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

* Guard current browser tab exports (#75731)

* fix(browser): guard current tab exports

* fix(browser): expand tab guard coverage

* fix(browser): guard tab reads

* fix(browser): guard screenshot route

* changelog: PR #75731

---------

Co-authored-by: Devin Robison <[email protected]>

* fix(update): finish post-core package updates

* fix(update): exit post-core package child

* docs(changelog): note update and slack fixes

* Harden Windows command wrapper resolution (#77472)

* Harden Windows command wrapper resolution

* clawsweeper: route Windows cmd.exe wrapper through getWindowsInstallRoots

Replace the local SystemRoot/windir/SYSTEMROOT/WINDIR scan in
resolveTrustedWindowsCmdExe with the shared getWindowsInstallRoots()
resolver from src/infra/windows-install-roots.ts. The shared resolver
already rejects UNC paths, root-relative values, semicolon-delimited
path-lists, and missing-drive-letter roots, and prefers registry-derived
roots over env, so the wrapper-launch trust boundary now matches the
existing Windows install-root boundary on main.

Tests:
- _resetWindowsInstallRootsForTests in beforeEach so cached roots track
  per-test process.env mutations
- expectedTrustedCmdExe helper now joins the resolved systemRoot, so the
  expected wrapper executable matches the production resolver on Linux
  CI (where it falls back to DEFAULT_WINDOWS_SYSTEM_ROOT)
- new "rejects unsafe Windows root values" test covers UNC,
  semicolon-delimited path-list, root-relative, and bare-relative
  SystemRoot inputs

* Add CHANGELOG entry for #77472 Windows command wrapper hardening

* clawsweeper: stub registry probe in Windows wrapper tests

On real Windows CI runners getWindowsInstallRoots() reads the canonical
SystemRoot from the registry (e.g. C:\WINDOWS) before falling back to
process.env, which shadowed the env-only setup in the ComSpec-poisoning
and unsafe-root tests and produced casing mismatches like
"C:\WINDOWS\System32\cmd.exe" vs the expected "C:\Windows\...". Pass a
queryRegistryValue stub returning null in beforeEach (and inside the
unsafe-root loop) so install-root resolution is fully driven by the
test's process.env setup on every platform.

* clawsweeper: overwrite WINDIR alongside SystemRoot in unsafe-root test

Real Windows runners did not honor `delete process.env.windir`, so the
unsafe-root iteration's WINDIR fallback still resolved to the canonical
`C:\WINDOWS` and produced a casing mismatch against the expected default
`C:\Windows\System32\cmd.exe`. Set both `SystemRoot` and `WINDIR` to the
unsafe payload so every install-root env source is rejected by
`normalizeWindowsInstallRoot` and the resolver falls through to
`DEFAULT_WINDOWS_SYSTEM_ROOT`.

* ci(release): recover Windows packaged update no-restart timeout

* fix(plugins): trust official diagnostics installs (#77516)

* fix(plugins): trust chat catalog installs

* fix(agents): honor hook bootstrap content (#77501)

* Problem: `agent:bootstrap` hooks can inject `BOOTSTRAP.md` content, but embedded-runner bootstrap routing decided whether bootstrap was pending before hook-adjusted files were considered.
* Fix: preload hook-adjusted bootstrap files before routing, treat non-empty hook-provided `BOOTSTRAP.md` as pending and accessible bootstrap content, and reuse the preloaded files when building Project Context.
* Tests: added routing + context-engine regression coverage for hook-injected bootstrap content.

Co-authored-by: ificator <[email protected]>
Co-authored-by: galiniliev <[email protected]>

* fix(update): stage npm-prefix package updates cleanly

Co-authored-by: Josh Lehman <[email protected]>

* fix(update): keep plugin install runtime aliases stable

* test(package): cover stale source plugin shadows

Co-authored-by: Vincent Koc <[email protected]>

* fix(plugins): fall back from invalid beta npm updates

* fix(active-memory): stabilize timeout partial recovery

* fix(browser): guard existing-session screenshots

* test(plugins): harden kitchen sink live gauntlet

* fix(gateway): clear reply run before followup drain

* fix(openrouter): keep DeepSeek V4 reasoning effort valid (#77423)

Summary:
- The PR removes `max` from OpenRouter DeepSeek V4 thinking profiles, maps stale OpenRouter `max` overrides to `xhigh`, preserves direct DeepSeek behavior, and updates docs, tests, and changelog.
- Reproducibility: yes. Source inspection on current main shows OpenRouter DeepSeek V4 advertises `max` and se ... ffort: "max"`, matching the linked 400 logs; I did not need a live OpenRouter request for this assist pass.

Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Addressed earlier ClawSweeper review findings before merge.
- Included post-review commit in the final squash: docs(changelog): credit OpenRouter duplicate fix
- Included post-review commit in the final squash: fix(openrouter): keep DeepSeek V4 reasoning effort valid

Validation:
- ClawSweeper review passed for head becdea4223be0cbb6806d92d11ca4307d19bfc3f.
- Required merge gates passed before the squash merge.

Prepared head SHA: becdea4223be0cbb6806d92d11ca4307d19bfc3f
Review: https://github.com/openclaw/openclaw/pull/77423#issuecomment-4372880583

Co-authored-by: sallyom <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* fix(update): exit post-core resume without result path

* fix(update): isolate plugin sync failures

Disable and skip plugins that fail package-update plugin sync so broken plugin packages do not fail an otherwise successful OpenClaw update.

* test(plugins): source Testbox auth for kitchen sink live

* fix(agents): avoid duplicate generated media attachments

* fix(cli): bound sessions list output

* fix(update): use absolute npm script shell

* refactor: centralize reply followup drain lifecycle

* test(browser): mirror route URL guard in existing-session helper

* docs(changelog): note npm script shell update fix

* fix(openai): default direct responses to sse

* fix(plugins): treat CalVer correction versions as compatible with plugin API ranges (#77450)

* fix(plugins): accept CalVer correction plugin API hosts

Fixes #77293

* docs(changelog): credit plugin api calver fix pr

---------

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

* fix(active-memory): skip sub-agent gracefully when no memory tools registered (#77506) (#77515)

* fix(active-memory): skip sub-agent gracefully when no memory tools registered (#77506)

When memory-core and memory-lancedb are both absent, the embedded
memory sub-agent would throw 'No callable tools remain after resolving
explicit tool allowlist', which propagated as a noisy warning through
the before_prompt_build hook. Catch this specific error in
runActiveMemorySubAgent and return an empty NONE result so the
gateway log stays clean and the sub-agent run is skipped without
disrupting the parent session.

* fix(active-memory): skip missing memory-tool subagent runs

* fix(active-memory): match inherited missing memory tool errors

* fix(active-memory): preserve policy-filtered memory errors

---------

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Tak Hoffman <[email protected]>

* fix(telegram): honor topic requireMention precedence

Telegram forum-topic requireMention config now takes precedence over persisted activation state, with focused regression coverage.\n\nFixes #49864.\nThanks @Panniantong.

* fix(secretrefs): resolve external channel contracts in dist/ sidecars (#77421)

* fix(secretrefs): resolve external channel contracts in dist/ sidecars

Externalized channel plugins published to npm (e.g. @openclaw/discord
since 2026.5.2) keep their compiled secret-contract-api artifact under
<rootDir>/dist/, per the package.json `openclaw.runtimeExtensions`
convention. The runtime contract loader added in #76449 only searched
the rootDir, so npm-installed plugins silently dropped their channel
SecretRef contracts: the runtime snapshot left `channels.<id>.token`
as an unresolved SecretRef, the plugin's `isConfigured` check then
returned false, and the gateway recorded `error: not configured`
without firing the usual channel startup logs.

Look in `<rootDir>/dist/` as well as `<rootDir>/`, preferring dist
when running from a built openclaw artifact and rootDir when running
from source. The new `loads dist/ secret-contract-api sidecars …`
test in channel-contract-api.external.test.ts mirrors the real
npm-package layout and fails without this change.

Refs #76371. Fixes #77416.

* docs: credit changelog contributor

---------

Co-authored-by: Magpie <magpie@local>
Co-authored-by: joshavant <[email protected]>

* chore: update dependencies

* fix(docker): prune external plugin dist (#77547)

* fix: harden startup readiness and discord replies

(cherry picked from commit 3956672106b3387d42427a485a9ca01e77f3b78f)

* fix(discord): preserve non-text payloads in reply scrub

* fix: clean up startup readiness PR docs

* fix: preserve visible Discord labeled replies

* fix(agents): preserve workspace metadata reuse

Pass the resolved agent workspace through hot model refresh paths so workspace-scoped plugin metadata snapshots can be reused.

Refs #77519.
Refs #77532.

* test: make global install shell test portable

* fix(config): prefer plugin ids for built-in channel claims

Prefer the manifest plugin id when auto-allowlisting configured built-in channel aliases, with regression coverage for alias/id split plugins and same-name official channel plugins.

* fix(model): guide runtime allowlist repairs

* fix(telegram): clarify model picker runtime scope

* docs(changelog): note model runtime switch repair UX

* fix(docker): normalize plugin build args

* fix(doctor): preserve active auth profile metadata

* fix(codex/app-server): stable mirror idempotency to prevent transcript loss (#77046)

* fix(codex/app-server): stable mirror idempotency to prevent transcript loss

* Changelog: note codex/app-server transcript mirror dedupe stabilization (#77046)

* fix(plugins): emit actionable install hint for externalized channel plugins (#77502)

Fixes #77483.\n\n- Suggest catalog-backed install commands for missing official external plugins in config validation.\n- Preserve stale/remove wording for non-catalog missing plugins.\n- Add regression coverage for plugins.entries and plugins.allow warnings.\n\nVerification:\n- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/config/validation.ts src/config/config.plugin-validation.test.ts\n- pnpm test src/config/config.plugin-validation.test.ts src/commands/doctor/shared/missing-configured-plugin-install.test.ts\n- pnpm crabbox:run -- --provider blacksmith-testbox ... pnpm check:changed\n- GitHub CI green on d1b1b1044403a2072fe10631a70fb13438990440

* Harden Codex harness control surfaces (#77459)

* fix(scripts): find codex protocol source from worktrees

* fix(test): keep codex harness docker caches writable

* fix(test): relax live codex cache mount permissions

* test(codex): add live docker harness debug output

* fix(test): detect numeric ci env in codex docker harness

* fix(codex): skip duplicate agent-command telemetry

* fix(tooling): skip sparse-missing oxlint tsconfig

* fix(tooling): route changed checks through testbox

* fix(qa): keep coverage json source-clean

* fix(test): preflight codex docker auth

* fix(codex): validate bind option values

* fix(codex): parse quoted command arguments

* fix(codex): reject extra control args

* fix(codex): use content for blank bound prompts

* fix(codex): decode local image file urls

* fix(codex): treat local media urls as images

* fix(codex): keep windows media paths local

* fix(codex): reject malformed diagnostics confirmations

* fix(codex): reject malformed resume commands

* fix(codex): reject malformed thread actions

* fix(codex): reject malformed turn controls

* fix(codex): reject malformed model controls

* fix(codex): resolve empty user input prompts

* fix(codex): enforce user input options

* fix(codex): reject ambiguous computer-use actions

* fix(codex): ignore stale bound turn notifications

* test(gateway): close task registries in gateway harness

* test(gateway): route cleanup through task seams

* fix(codex): describe current permission approvals

* fix(codex): disclose command approval amendments

* fix(codex): preserve approval detail under truncation

* fix(codex): propagate dynamic tool failures

* test(codex): align dynamic tool block contract

* fix(codex): reject extra read-only command operands

* fix(codex): escape command readout fields

* fix(codex): escape status probe errors

* fix(codex): narrow formatted thread details

* fix(codex): escape successful status summaries

* fix(codex): escape bound control replies

* fix(codex): escape user input prompts

* fix(codex): escape control failure replies

* fix(codex): escape approval prompt text

* test(codex): narrow escaped reply assertions

* test(codex): complete strict reply fixtures

* test(codex): preserve account fixture literals

* test(codex): align status probe fixtures

* fix(codex): satisfy sanitizer regex lint

* fix(codex): harden command readouts

* fix(codex): harden bound image inputs

* fix(codex): sanitize command failure replies

* test(codex): complete rate limit fixture

* test(tooling): isolate postinstall compile cache fixture

* fix(codex): keep app-server event ownership explicit

---------

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

* ci(release): split release soak validation

* feat: add gateway stall diagnostics

* fix: enable sync io tracing in gateway watch

* fix: preserve gateway watch trace overrides

* docs: add gateway diagnostics changelog

* fix: clarify slack socket retry errors

* fix: clean up orphaned child processes (#77481)

* fix: forward launcher respawn signals

* docs: explain respawn signal exit timer

* fix: centralize launcher respawn supervision

* fix: include respawn helper in duplicate scan

* fix: keep launcher respawn bridge local

* fix(channels): preserve channel aliases in plugin probes

Key package-state probes, env/config presence, and read-only command defaults by channel id instead of manifest plugin id so alias-owned channel plugins keep setup/native-command detection working.

* fix(gateway): quiet benchmark watch output

* fix(mattermost): clarify model picker runtime behavior

* fix: repair release validation checks

* fix(lint): cover diagnostic phase events

* fix(gateway): route watch trace spam to artifacts

* test(doctor): mock bundled channel ids

* fix(config): register bundledMode in zod schema and help text

Addresses review feedback: adds bundledMode to the strict plugins zod
object so the config option passes validation, and adds schema.help
documentation for the field.

* fix(plugins): add bundledMode to gate runtime provider discovery by allowlist

When plugins.bundledMode is set to "respect-allow", runtime provider
discovery paths honor plugins.allow for bundled plugins instead of
force-loading all providers. Default "compat" preserves existing behavior.

Closes #75575

* fix(plugins): respect allowlist for web provider fallback

* test(plugins): type bundled public artifact mock

* fix(plugins): rename bundled allowlist discovery policy

* docs(config): refresh bundled discovery baseline

* fix(plugins): default bundled discovery to allowlist

* test(doctor): preserve bundled discovery literal type

* test(plugins): make loader compat contract explicit

* fix(plugins): preserve bundled allowlist edges

* fix(plugins): normalize compat allowlist aliases

* fix(discord): prefer IPv4 for gateway startup

* fix: log gateway model mode defaults

* fix(docker): pin container-side workspace and config dirs in compose

Fixes #77436

* fix: simplify gateway model startup modes

* test(extensions): refresh dependency-backed assertions

* test(docker): align published upgrade timeout

* fix(plugins): recover managed-npm external plugins after package-manager upgrade

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

* fix(doctor): repair allow-only official plugins

* fix(plugins): include json5 in memory runtime deps

* fix(plugins): include json5 in memory runtime deps

* chore(ci): allow bundled runtime json5 dep

* fix(openai-codex): avoid stale Responses replay state

* fix(openai-codex): match codex replay identity

* docs(changelog): credit codex replay fix

* fix(dashboard): guide manual token auth fallback

Summary:
- Add a redaction-safe dashboard fallback hint when tokenized URL delivery fails.
- Document the manual auth path and update the changelog.

Verification:
- PR CI exact head 48ccb97c0843c8b2e9640ac68adab6d311605705 green for relevant CI/security checks.
- pnpm test src/commands/dashboard.links.test.ts src/commands/dashboard.test.ts
- pnpm exec oxfmt --check --threads=1 src/commands/dashboard.ts src/commands/dashboard.links.test.ts
- pnpm format:docs:check
- pnpm docs:check-mdx
- pnpm docs:check-i18n-glossary
- targeted markdownlint for docs/cli/dashboard.md and docs/web/dashboard.md

* fix: sync Codex app-server protocol (#77578)

* fix: sync codex app-server protocol

* docs: add codex protocol changelog

* fix: refresh codex protocol schemas

* fix(telegram): derive media placeholders from MIME

Fixes #69793.

Verification:
- repro before fix: `pnpm test:serial extensions/telegram/src/bot-message-context.body.test.ts -- --reporter=verbose` failed 3 new cases with `<media:image>` returned for non-image/mixed saved media
- `pnpm test:serial extensions/telegram/src/bot-message-context.body.test.ts -- --reporter=verbose` passed 9 tests after fix
- `pnpm exec oxfmt --check --threads=1 extensions/telegram/src/bot-message-context.body.ts extensions/telegram/src/bot-message-context.body.test.ts`
- `git diff --check`
- `OPENCLAW_TESTBOX=1 pnpm testbox:run --id tbx_01kqtnnhpg6rk1225tbb7109kf -- "pnpm check:changed"` passed

* test(plugins): add kitchen sink rpc walk

* test: add slack onboarding channel smoke (#77575)

* fix: keep runtime prompt context out of system prompt (#77521)

* fix(plugins): keep explicit web providers on fast path

* test(agents): remove redundant payload casts

* Surface Codex usage-limit reset details in chat replies (#77557)

* fix(codex): surface usage limit reset details

* fix(codex): satisfy extension lint

* fix: surface codex runtime failures in tool-only replies

* fix(release): refresh plugin sdk api gate

Refresh release baseline hashes and raise the Plugin SDK API baseline heap cap so release preflight reports real drift instead of OOMing.

* fix(openai): route Codex audio to transcription model

* test(plugins): refresh kitchen sink docker fixture

* test(live): run cache probe with node

* fix(acpx): resolve plugin manifest from bundled runtime

* docs(changelog): credit @pashpashpash for Codex usage-limit reset surfacing

#77557 added user-facing surfacing of Codex app-server usage-limit reset
details and OpenClaw-owned runtime failure notices through tool-only
source-reply mode, but the entry landed without contributor attribution.
Add the merging PR ref and credit the human contributor @pashpashpash
per CLAUDE.md changelog-attribution rules.

* test(plugins): update kitchen sink prerelease canary version

* fix(discord): fail dropped final reply delivery

* docs: thank Discord reply fix contributor (#77596)

* Add instructions for how to setup slack for QA tests (#77606)

* docs(cli): document gateway restart --safe in command options

The `gateway restart` Command-options accordion only listed `--force`,
`--wait`, and `--json` even though `--safe` is a fully-supported flag
(documented in the prose at line 112 and rejected by lifecycle.ts when
combined with --force/--wait). Add --safe to the option list and a
Lifecycle-behavior bullet that explains the preflight-defer behavior
plus its mutual exclusion with --force and --wait, matching
src/cli/daemon-cli/lifecycle.ts:153-156.

* perf(plugins): reuse compatible metadata snapshots

Reuse compatible workspace-scoped plugin metadata snapshots for unscoped model catalog and manifest-contract readers while preserving env/config/workspace compatibility checks.

Also updates the stale kitchen-sink prerelease canary assertion to the current script default.

Fixes #77519.
Related #77532.

* fix(agents): mediate async media completions

* docs(help,security): cross-reference auth list and trusted-env-proxy

Two missing cross-references uncovered by the 24-hour doc audit:

- docs/help/faq-models.md: link to `openclaw models auth list` from the
  "What is an auth profile?" accordion. The command was added in
  23eb44b045 but the FAQ never pointed users at it.
- docs/security/network-proxy.md: list `tools.web.fetch.useTrustedEnvProxy`
  in Related Proxy Terms. The opt-in is fully documented in
  docs/tools/web-fetch.md but the proxy reference page omitted the
  cross-reference, leaving the page incomplete for proxy-state triage.

* test(live): retry cache probe text misses

* fix(secrets): preserve auth profile key refs during provider scrub (#77489)

* fix(secrets): preserve auth profile key refs during provider scrub

* Add changelog for secrets apply fix

* Seed auth profile ref for scrub regression

* fix(secrets): guard auth profile ref scrub

---------

Co-authored-by: Vincent Koc <[email protected]>

* fix: repair stale session route state in doctor

* test: use latest kitchen sink canary

* build: bump axios override

* docs: require live proof before landing

* fix(media): use r+ for Windows media fsync (#76593)

Fix Windows media offload failures by opening saved attachment temp files read/write before fsync, preserving the non-truncating temp-file write path while allowing Windows FlushFileBuffers to succeed.

Also adds the required changelog entry.

Tests:
- pnpm test src/media/store.test.ts src/gateway/chat-attachments.test.ts
- pnpm check:changed

Thanks @qq230849622-a11y.

Co-authored-by: 李claw <[email protected]>
Co-authored-by: Brad Groux <[email protected]>

* fix(lsp): resolve Windows .cmd shims (#75343)

Resolve Windows npm .cmd shim startup failures for bundled LSP servers by routing LSP process spawning through the shared Windows spawn resolver with a sanitized child environment.

The change reuses existing PATH/PATHEXT and .cmd shim handling, keeps non-Windows behavior unchanged, and adds focused regression coverage for resolver wiring, env sanitization, and spawn materialization.

Fixes #75352.

Tests:
- pnpm test src/agents/pi-bundle-lsp-runtime.windows-spawn.test.ts src/agents/pi-bundle-lsp-runtime.test.ts
- pnpm check:changed

Thanks @ElliotDrel.

Co-authored-by: Elliot Drel <[email protected]>
Co-authored-by: Brad Groux <[email protected]>

* test(plugins): align metadata snapshot policy fixtures

* test(live): scale gateway profile timeout

* test(live): use low reasoning for cache probes

* feat(agents): add post-compaction loop guard module + config

Pure module with unit tests; not yet wired into runner. The guard arms
after auto-compaction-retry and aborts when the same (tool, args, result)
triple repeats within the configured window.

Refs #77474

* fix(agents): address review feedback on post-compaction loop guard

- Add PostCompactionLoopPersistedError.fromVerdict factory.
- Add unit tests for the error class + fromVerdict adapter.
- Disabled guard is now truly dormant (no state mutation when enabled=false).
- Tighten help text for postCompactionGuard.enabled.

Refs #77474

* feat(agents): wire post-compaction loop guard into pi-embedded-runner

Arms the guard at each of the three compaction-success points in
run.ts and observes tool-call outcomes from the diagnostic session
state's toolCallHistory after each attempt. Aborts with
PostCompactionLoopPersistedError when the same (tool, args, result)
triple repeats windowSize times within the post-compaction window.

Refs #77474

* fix(agents): make post-compaction guard config valid + observation trim-resilient

Two correctness fixes from code review.

1. Zod schema (src/config/zod-schema.agent-runtime.ts) was strict and
   rejected tools.loopDetection.postCompactionGuard.* keys at validation
   time, making the guard's documented configurability inaccessible at
   gateway startup. Adds ToolLoopPostCompactionGuardSchema with both
   optional fields and wires it into ToolLoopDetectionSchema.

2. The runner observation cursor in pi-embedded-runner/run.ts used
   absolute indices into state.toolCallHistory, but that array is
   trimmed at historySize (default 30). Once the buffer was full, new
   records shifted out from under the cursor and the guard silently
   missed every loop in long-running sessions. Replaces the index
   cursor with a monotonic toolOutcomeSeq on SessionState that
   recordToolCallOutcome bumps on each observable push (unmatched
   branch only, mirroring the prior cursor's effective semantics).
   The runner now reads the most recent (currentSeq - lastSeq) entries
   from the tail of toolCallHistory, which is trim-resilient.

Adds zod parse tests for the new config keys (valid, empty, unknown
key, non-positive, non-integer) and a runner regression test that
seeds toolCallHistory at the trim cap before triggering a
post-compaction loop, asserting the abort still fires.

Refs #77474

* fix(agents): observe matched post-compaction tool outcomes

* test(agents): avoid redundant guard scope spread

* fix(agents): observe post-compaction guard live

* refactor(agents): thread post-compaction guard observer

* fix(agents): honor scoped post-compaction guard config

* chore(config): refresh post-compaction guard labels

* refactor(agents): use loop detection switch for post-compaction guard

* fix(agents): abort post-compaction loops out-of-band

* chore(config): refresh merged baseline hash

* docs(channels): inline Slack manifest into Quick Setup with Recommended/Minimal variants

The Quick Setup steps in docs/channels/slack.md previously sent users to
the `#manifest-and-scope-checklist` anchor lower on the page to copy the
manifest, breaking the copy-paste flow. Pull the manifest inline as a
Mintlify <CodeGroup> for both Socket Mode and HTTP Request URLs tabs and
add a Minimal variant for workspaces that restrict scopes (drops
files:*, reactions:*, pins:*, mpim:*, emoji:read, usergroups:read while
keeping DMs, channel/group history, mentions, App Home, and slash
commands). Recommended matches extensions/slack/src/setup-shared.ts.
Existing Manifest and scope checklist section stays as the canonical
per-scope reference.

Cross-link from docs/concepts/qa-e2e-automation.md so QA maintainers see
the production manifest reference, while keeping the QA Driver/SUT pair
of manifests inline (the lane intentionally needs two distinct apps so
its shape is different from a single-app production install).

* docs(doctor): clarify configured plugin repair (#77613)

* ci(release): speed up focused release reruns

* fix: honor embedded runtime tool allowlists (#77609)

* fix: honor embedded runtime tool allowlists

* fix: preserve plugin allowlist filtering

* fix: gate bundled lsp allowlists

* docs(channels): add Socket vs HTTP comparison and explain shared URL fields

The Slack docs jumped straight from intro into the Quick Setup tabs
without telling readers when to pick each transport. Add a Choosing
Socket Mode or HTTP Request URLs section above Quick Setup with a
concern-by-concern table (public URL, outbound network, tokens, dev
laptops, scaling, multi-account, slash command transport, signing,
recovery) plus a Note pointing at the right default for each shape.

Also add an Info block under the HTTP Quick Setup manifest explaining
why the manifest carries three url fields (slash_commands[].url,
event_subscriptions.request_url, interactivity.request_url) — Slack's
manifest schema requires them spelled out separately even though
OpenClaw routes by payload type, and slash commands silently no-op
without their url field in HTTP mode.

* fix(infra): skip POSIX tmp path on Windows (#73533)

Skip the POSIX `/tmp/openclaw` preferred path on Windows so temp files land under the trusted `os.tmpdir()`/`%TEMP%`-based `openclaw-<uid>` path instead of `C:\tmp\openclaw`.

Add regression coverage for Windows path selection and the WhatsApp media temp directory integration, plus a changelog entry.

Fixes #60713.

Tests:
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/infra/tmp-openclaw-dir.ts src/infra/tmp-openclaw-dir.test.ts extensions/whatsapp/src/media.test.ts
- pnpm test src/infra/tmp-openclaw-dir.test.ts extensions/whatsapp/src/media.test.ts
- pnpm check:changed

Thanks @juan-flores077.

Co-authored-by: Juan Flores <[email protected]>
Co-authored-by: Brad Groux <[email protected]>

* chore(release): prepare 2026.5.4 beta 2

* fix(release): prune externalized plugin chunks

* fix(build): route externalized plugin chunks

* fix(build): route externalized plugin entry chunks

* fix: recover missing Codex bound threads

(cherry picked from commit a373468d825224c92051dc2e50b717fbe75c401c)

* fix(plugins): repair missing openclaw peer links on update

(cherry picked from commit 2e8761c5c1541496667201ba02716ab90eb24ee3)

* docs: note plugin peer-link update repair

(cherry picked from commit 712aa96a8fb3589bd39ab0c2e071395bc612ad1d)

* fix: start configured generation providers

(cherry picked from commit 0eb06caae3807679b23d2c20a5b464fa46fdc556)

* fix: slack mention-gating thread participation

(cherry picked from commit cf3ce08b910ee13f84ec04970f2d852dbbd36a32)

* fix: explain missing git during plugin install

(cherry picked from commit a91c17c426f9bf5c0e201f0da99064e088e251fa)

* fix(update): authenticate restart health probes

(cherry picked from commit b546aa91e19b3411ccdbc7c4189c2fdac9415869)

* fix(whatsapp): normalize onboarding allowlist numbers

Normalize WhatsApp onboarding allowlist entries to digit-only WhatsApp IDs and reject invalid owner-phone inputs during prompt validation.

(cherry picked from commit 68a500c465cc2a44561c46d8ee14a01e471097f7)

* fix(telegram): reuse preview for long text finals (#77658)

* fix(telegram): reuse preview for long text finals

* test(qa): cover long telegram finals

* fix(qa): satisfy extension lint

* fix(qa): keep telegram long final fixture to two chunks

* test(telegram): cover three chunk finals

* fix(telegram): force long final preview boundary

(cherry picked from commit e03fe1e28965c5edbf8735620757c2f5d28b29e7)

* fix(plugins): honor beta channel for auto installs

(cherry picked from commit b0f841ef37dbf3313487a3068a51c2751ddf4fb3)

* test: align beta plugin repair expectations

* fix(gateway): skip IPv6 loopback binding on Windows (#69701)

Bind the default loopback gateway listener only to `127.0.0.1` on Windows so libuv dual-stack `::1` behavior cannot wedge localhost HTTP requests.

Also keeps non-Windows dual-loopback behavior covered, replaces the redundant Windows passthrough test with guard coverage, and adds the required changelog entry.

Fixes #69674.

Tests:
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/gateway/net.ts src/gateway/net.test.ts
- pnpm test src/gateway/net.test.ts
- pnpm check:changed
- GitHub required checks: green

Thanks @SARAMALI15792.

Co-authored-by: saram ali <[email protected]>
Co-authored-by: Brad Groux <[email protected]>
(cherry picked from commit 978bc53e80cccdc23d42324b18c4d20cd4749315)

* fix(agents): enforce exact skill path from <available_skills> [AI-assisted] (#74161)

Summary:
- The PR updates agents skill prompt guidance to require exact `<location>` paths for single- and multi-skill selection, adds prompt assertions, and records the fix in the changelog.
- Reproducibility: yes. Static source reproduction is enough: current main lacks the exact-`<location>` guard  ... illsSection()`, while the PR diff adds it to both selection branches and asserts the resulting prompt text.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: enforce exact skill paths for all skill matches

Validation:
- ClawSweeper review passed for head 743c9840c117312646ff6065ce4939f6555c5c0b.
- Required merge gates passed before the squash merge.

Prepared head SHA: 743c9840c117312646ff6065ce4939f6555c5c0b
Review: https://github.com/openclaw/openclaw/pull/74161#issuecomment-4341488109

Co-authored-by: tianguicheng <[email protected]>
Co-authored-by: sallyom <[email protected]>
(cherry picked from commit c739088d62b9e3589f6a5f9bb31cdc73688ca20f)

* fix(sandbox): support Windows drive-letter bind sources

Accept drive-absolute Windows sandbox Docker bind sources in config and runtime validation while keeping blocked-path and allowed-root comparisons case-insensitive for Windows drive paths.

Also remove a stale WhatsApp setup import that blocked extension lint after the rebase.

Co-authored-by: 6607changchun <[email protected]>
Co-authored-by: Brad Groux <[email protected]>
(cherry picked from commit d02fbc6116ed9cbd501ad6a1e4d08f3fc71c1dd8)

* chore(release): bump to 2026.5.4-beta.3

* chore(release): refresh plugin SDK API baseline

* fix(diagnostics): drop stale session recovery event cases

* ci: parallelize release publish workflows

* chore(release): bump to 2026.5.4

---------

Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Jesse Merhi <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Val Alexander <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dallin Romney <[email protected]>
Co-authored-by: Josh Lehman <[email protected]>
Co-authored-by: Val Alexander <[email protected]>
Co-authored-by: Eva <[email protected]>
Co-authored-by: 100yenadmin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Co-authored-by: Kevin Lin <[email protected]>
Co-authored-by: hcl <[email protected]>
Co-authored-by: Pavan Kumar Gondhi <[email protected]>
Co-authored-by: zhang-guiping <[email protected]>
Co-authored-by: Michael Appel <[email protected]>
Co-authored-by: Devin Robison <[email protected]>
Co-authored-by: Mert Başar <[email protected]>
Co-authored-by: Mert Basar <[email protected]>
Co-authored-by: Satoshi F. <[email protected]>
Co-authored-by: galiniliev <[email protected]>
Co-authored-by: stain lu <[email protected]>
Co-authored-by: stainlu <[email protected]>
Co-authored-by: Devin Robison <[email protected]>
Co-authored-by: scoootscooob <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: VACInc <[email protected]>
Co-authored-by: Syu <[email protected]>
Co-authored-by: SYU8384 <[email protected]>
Co-authored-by: Agustin Rivera <[email protected]>
Co-authored-by: Brad <[email protected]>
Co-authored-by: ificator <[email protected]>
Co-authored-by: galiniliev <[email protected]>
Co-authored-by: Sally O'Malley <[email protected]>
Co-authored-by: Penchan <[email protected]>
Co-authored-by: pingu <[email protected]>
Co-authored-by: Tak Hoffman <[email protected]>
Co-authored-by: Pnant <[email protected]>
Co-authored-by: Mogglemoss <[email protected]>
Co-authored-by: Magpie <magpie@local>
Co-authored-by: joshavant <[email protected]>
Co-authored-by: Satoshi <[email protected]>
Co-authored-by: Brandon <[email protected]>
Co-authored-by: Chunyue Wang <[email protected]>
Co-authored-by: pashpashpash <[email protected]>
Co-authored-by: dougbtv <[email protected]>
Co-authored-by: Shubhankar Tripathy <[email protected]>
Co-authored-by: mkdev11 <[email protected]>
Co-authored-by: praveen9354 <[email protected]>
Co-authored-by: Patrick Erichsen <[email protected]>
Co-authored-by: Sarah Fortune <[email protected]>
Co-authored-by: 李claw <[email protected]>
Co-authored-by: 李claw <[email protected]>
Co-authored-by: Brad Groux <[email protected]>
Co-authored-by: Elliot Drel <[email protected]>
Co-authored-by: Eduardo Piva <[email protected]>
Co-authored-by: Juan Flores <[email protected]>
Co-authored-by: Kelaw - Keshav's Agent <[email protected]>
Co-authored-by: pickaxe <[email protected]>
Co-authored-by: Bek <[email protected]>
Co-authored-by: saram ali <[email protected]>
Co-authored-by: 兰之 <[email protected]>
Co-authored-by: tianguicheng <[email protected]>
Co-authored-by: 6607changchun <[email protected]>
lxe pushed a commit to lxe/openclaw that referenced this pull request May 6, 2026
…t paths [AI] (openclaw#74458)

* fix: address issue

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* changelog: PR openclaw#74458

---------

Co-authored-by: Devin Robison <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants