openclaw - ✅(Solved) Fix [Bug]: exec-policy still rejects symlinked ~/.openclaw after #72377 replacement for #64663 [6 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72572Fetched 2026-04-28 06:34:22
View on GitHub
Comments
0
Participants
1
Timeline
8
Reactions
0
Author
Participants
Timeline (top)
referenced ×5cross-referenced ×3

openclaw exec-policy preset yolo still fails when ~/.openclaw is a symlink, even after replacement PR #72377 landed and closed #64663.

#72377 fixed only the case where OPENCLAW_HOME itself is a symlinked trusted root. It still rejects a symlinked ~/.openclaw path component under the normal OS home directory, which is a common setup for users who manage OpenClaw config with GNU Stow or similar dotfile tooling.

Error Message

throw new Error(Refusing to traverse symlink in exec approvals path: ${current});

Root Cause

openclaw exec-policy preset yolo still fails when ~/.openclaw is a symlink, even after replacement PR #72377 landed and closed #64663.

#72377 fixed only the case where OPENCLAW_HOME itself is a symlinked trusted root. It still rejects a symlinked ~/.openclaw path component under the normal OS home directory, which is a common setup for users who manage OpenClaw config with GNU Stow or similar dotfile tooling.

Fix Action

Fixed

PR fix notes

PR #72377: fix: allow trusted exec approvals home symlinks

Description (problem / solution / changelog)

Summary

  • Repair the exec approvals path validation regression for symlinked OPENCLAW_HOME / ~/.openclaw setups.
  • Keep deeper symlink traversal protection intact and cover the accepted and rejected cases with focused tests.
  • Preserve contributor credit from #64663, with related context from #68417 and #65736 where applicable.

Validation

  • pnpm -s vitest run src/infra/exec-approvals-store.test.ts
  • pnpm check:changed

Refs: #64663, #68417, #65736, #62917, #64050.

ProjectClownfish replacement details:

  • Cluster: ghcrawl-191457-agentic-merge
  • Source PRs: https://github.com/openclaw/openclaw/pull/64663, https://github.com/openclaw/openclaw/pull/68417, https://github.com/openclaw/openclaw/pull/65736
  • Credit: Preserve credit for FunJim via #64663 as the canonical contributor branch and source of the symlinked OPENCLAW_HOME fix.; Credit acinader and #68417 if the repaired implementation borrows the OPENCLAW_STATE_DIR symlink trusted-root approach.; Credit oinoom and #65736 if the repaired implementation includes OPENCLAW_STATE_DIR path/socket behavior or exec-approvals-effective.ts changes.
  • Validation: pnpm -s vitest run src/infra/exec-approvals-store.test.ts; pnpm check:changed
  • Repair fallback: ::error file=src/infra/exec-approvals-store.test.ts,line=19,endLine=19,col=5,endColumn=26,title=eslint(no-unused-vars)::Variable 'assertSecureOwnership' is assigned a value but never used. Unused variables should start with a '_'.

Found 0 warnings and 1 error.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/infra/exec-approvals-store.test.ts (modified, +21/-4)
  • src/infra/exec-approvals.ts (modified, +2/-4)

PR #72650: fix(exec-policy): accept trusted ~/.openclaw symlink at home boundary

Description (problem / solution / changelog)

Fixes #72572.

Problem

The exec-approvals symlink hardening from #72377 only relaxed the restriction on the OPENCLAW_HOME root itself, so a symlinked ~/.openclaw immediate child of a real home directory still trips assertNoSymlinkPathComponents():

``` Refusing to traverse symlink in exec approvals path: /Users/funjim/.openclaw ```

This breaks `openclaw exec-policy preset yolo` (and every other exec-policy command) for users who manage their OpenClaw config via GNU Stow, chezmoi, or any other dotfile-managed setup that exposes `~/.openclaw → ~/dotfiles/openclaw/.openclaw`.

Fix

Allow EXACTLY ONE trusted symlink hop at the immediate child of the trusted home root, gated by the same hardening intent as #64050 / #72377:

  1. Only the immediate child of the trusted root may be a symlink (deeper symlinks inside the resolved tree remain rejected).
  2. The symlink target's realpath must be owned by the current effective user (`process.geteuid()`).
  3. The symlink target must not be group- or other-writable (mode bits `0o022`).
  4. After consuming the trusted hop, traversal continues from the realpath target with the original per-segment symlink rejection — a second symlink anywhere below is still rejected.

Permissive on platforms without `process.geteuid` (Windows), where the OS ACL model already differs.

`ensureDir()` is taught to accept a `dir` whose `lstatSync` reports a symlink, but only after re-asserting the realpath target is a directory — `assertNoSymlinkPathComponents()` already vetted ownership/perms.

Tests

  • New: `accepts a symlinked ~/.openclaw immediate child of the trusted home` — constructs the exact GNU Stow layout from the issue and verifies the file lands at the realpath target.
  • Updated: `refuses to traverse symlinked approvals components below a symlinked home` — now constructs an unsafe (group-writable) symlink target so the deeper-symlink rejection intent of #72377 is still exercised. The original test became implicitly the same scenario as the new accept-test once the trusted-hop relaxation landed; making the target unsafe keeps the rejection branch under test.

All 18 `exec-approvals-store` tests pass; `pnpm tsgo:test` clean.

Diff

+92 / -3 across 2 production files + 1 test file + CHANGELOG.

Refs

  • Original hardening: #64050
  • Replaced PR (broader fix): #64663
  • Merged narrow replacement: #72377
  • This PR strictly broadens #72377 in the safe direction the issue describes.

Changed files

  • src/infra/exec-approvals-store.test.ts (modified, +32/-0)
  • src/infra/exec-approvals.ts (modified, +59/-3)

PR #72713: [codex] fix: allow trusted .openclaw symlink

Description (problem / solution / changelog)

Summary

Closes #72572.

This restores support for dotfile-managed ~/.openclaw directories while keeping exec approval paths hardened on both the Node and macOS node-host paths.

  • allow trusted first-level ~/.openclaw symlinks on POSIX after validating link ownership, link location, target ownership, target permissions, and stable resolved ancestors
  • keep Windows .openclaw symlink targets blocked until ACL validation exists
  • keep rejecting user-controlled chained symlink targets, deeper symlink traversal, and symlinked exec-approvals.json destinations
  • fail closed for unsafe approvals reads in runtime policy paths while keeping snapshot/control-plane reads usable
  • apply equivalent state-dir, JSON store, and socket-parent hardening on macOS, including symlinked OPENCLAW_STATE_DIR overrides and system /tmp//var symlink roots
  • document the supported symlink shape in approvals CLI docs

Validation

  • pnpm docs:list
  • pnpm exec oxfmt --check --threads=1 src/infra/exec-approvals.ts src/infra/exec-approvals-store.test.ts
  • pnpm test src/infra/exec-approvals-store.test.ts
  • swiftc -parse apps/macos/Sources/OpenClaw/ExecApprovals.swift apps/macos/Sources/OpenClaw/ExecApprovalsSocket.swift apps/macos/Sources/OpenClaw/NodeMode/MacNodeRuntime.swift apps/macos/Tests/OpenClawIPCTests/ExecApprovalsSocketPathGuardTests.swift apps/macos/Tests/OpenClawIPCTests/ExecApprovalsStoreRefactorTests.swift
  • git diff --check
  • pnpm check:changed (core lanes passed; apps lane stopped because swiftlint is not installed locally)
  • swift test --filter ExecApprovalsSocketPathGuardTests attempted; SwiftPM hung while downloading/building Sparkle artifact locally
  • codex review -c model="gpt-5.4" --base origin/main

AI-assisted: yes lobster-biscuit

Changed files

  • apps/macos/Sources/OpenClaw/ExecApprovals.swift (modified, +64/-37)
  • apps/macos/Sources/OpenClaw/ExecApprovalsSocket.swift (modified, +398/-14)
  • apps/macos/Sources/OpenClaw/NodeMode/MacNodeRuntime.swift (modified, +1/-1)
  • apps/macos/Tests/OpenClawIPCTests/ExecApprovalsSocketPathGuardTests.swift (modified, +328/-3)
  • apps/macos/Tests/OpenClawIPCTests/ExecApprovalsStoreRefactorTests.swift (modified, +61/-0)
  • docs/cli/approvals.md (modified, +3/-0)
  • src/infra/exec-approvals-store.test.ts (modified, +154/-7)
  • src/infra/exec-approvals.ts (modified, +264/-51)

Code Example

ln -s ~/workspace/openclaw-config/openclaw/.openclaw ~/.openclaw

---

ll ~/.openclaw
   # lrwxr-xr-x@ 1 funjim staff 44B Mar 21 18:28 /Users/funjim/.openclaw -> workspace/openclaw-config/openclaw/.openclaw

---

openclaw exec-policy preset yolo

---

🦞 OpenClaw 2026.4.26 (6d0e84a)Your personal assistant, minus the passive-aggressive calendar reminders.

Refusing to traverse symlink in exec approvals path: /Users/funjim/.openclaw

---

❯ ll ~/.openclaw
lrwxr-xr-x@ 1 funjim staff 44B Mar 21 18:28 /Users/funjim/.openclaw -> workspace/openclaw-config/openclaw/.openclaw

❯ openclaw exec-policy preset yolo

🦞 OpenClaw 2026.4.26 (6d0e84a)Your personal assistant, minus the passive-aggressive calendar reminders.

Refusing to traverse symlink in exec approvals path: /Users/funjim/.openclaw

---

assertNoSymlinkPathComponents(dir, resolveRequiredHomeDir());

---

const stat = fs.lstatSync(current);
if (stat.isSymbolicLink()) {
  throw new Error(`Refusing to traverse symlink in exec approvals path: ${current}`);
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

openclaw exec-policy preset yolo still fails when ~/.openclaw is a symlink, even after replacement PR #72377 landed and closed #64663.

#72377 fixed only the case where OPENCLAW_HOME itself is a symlinked trusted root. It still rejects a symlinked ~/.openclaw path component under the normal OS home directory, which is a common setup for users who manage OpenClaw config with GNU Stow or similar dotfile tooling.

Steps to reproduce

  1. Make ~/.openclaw a symlink, for example:

    ln -s ~/workspace/openclaw-config/openclaw/.openclaw ~/.openclaw
  2. Verify the symlink:

    ll ~/.openclaw
    # lrwxr-xr-x@ 1 funjim staff 44B Mar 21 18:28 /Users/funjim/.openclaw -> workspace/openclaw-config/openclaw/.openclaw
  3. Run:

    openclaw exec-policy preset yolo

Expected behavior

The command should succeed for a trusted first-level ~/.openclaw symlink owned by the current user, while still rejecting deeper symlink traversal inside the approvals path.

Actual behavior

It fails with:

🦞 OpenClaw 2026.4.26 (6d0e84a) — Your personal assistant, minus the passive-aggressive calendar reminders.

Refusing to traverse symlink in exec approvals path: /Users/funjim/.openclaw

OpenClaw version

2026.4.26 (6d0e84a)

Operating system

macOS

Install method

Any

Model

N/A

Provider / routing chain

N/A

Config file / key location

Exec approvals store under ~/.openclaw/exec-approvals.json

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Local repro:

❯ ll ~/.openclaw
lrwxr-xr-x@ 1 funjim staff 44B Mar 21 18:28 /Users/funjim/.openclaw -> workspace/openclaw-config/openclaw/.openclaw

❯ openclaw exec-policy preset yolo

🦞 OpenClaw 2026.4.26 (6d0e84a) — Your personal assistant, minus the passive-aggressive calendar reminders.

Refusing to traverse symlink in exec approvals path: /Users/funjim/.openclaw

Impact and severity

  • Affected: users who keep ~/.openclaw in a git-managed dotfiles repo and expose it via symlink (GNU Stow, chezmoi, manual symlink, etc.)
  • Severity: medium — exec approval policy commands fail in a common config-management setup
  • Frequency: always, when ~/.openclaw itself is a symlink under the normal home directory

Additional information

What happened across the PRs

  • #64663 proposed a broader fix for symlinked exec-approvals paths, including the common ~/.openclaw -> ... setup.
  • That PR was later closed and replaced by #72377.
  • #72377 merged a narrower change: it allows a symlinked OPENCLAW_HOME trusted root, but still rejects symlinked path components below that root.

The merged PR body explicitly says:

accept a symlinked OPENCLAW_HOME as the trusted approvals root while still rejecting symlinked .openclaw path components below it

That means the common default layout below still fails:

  • trusted root: /Users/<user>
  • approvals dir: /Users/<user>/.openclaw
  • ~/.openclaw is a symlink → still rejected by assertNoSymlinkPathComponents()

Current code path

On current main, ensureDir() still calls:

assertNoSymlinkPathComponents(dir, resolveRequiredHomeDir());

and assertNoSymlinkPathComponents() still rejects the first symlinked component it sees below the resolved home root:

const stat = fs.lstatSync(current);
if (stat.isSymbolicLink()) {
  throw new Error(`Refusing to traverse symlink in exec approvals path: ${current}`);
}

For a normal setup where resolveRequiredHomeDir() is /Users/funjim, the first traversed component is .openclaw, so the command still errors immediately.

Suggested fix direction

Please restore support for a trusted first-level ~/.openclaw symlink, not just a symlinked OPENCLAW_HOME.

A reasonable approach is the broader design from #64663:

  • allow the immediate .openclaw child under the trusted home dir to be a symlink
  • resolve it with realpathSync
  • validate the symlink target is owned by the current user and not group/other-writable
  • continue rejecting deeper symlinks inside the resolved .openclaw tree
  • ensure the final directory check follows the trusted symlink target safely rather than rejecting it unconditionally

In other words, the current fix handled:

  • OPENCLAW_HOME -> /some/real/home

but still misses:

  • ~/.openclaw -> ~/workspace/openclaw-config/openclaw/.openclaw

Related

  • Replaced PR: #64663
  • Merged replacement: #72377
  • Original hardening/regression source: #64050
  • Related but different symlink-path approval issue: #45595

extent analysis

TL;DR

The issue can be fixed by modifying the assertNoSymlinkPathComponents function to allow a trusted first-level ~/.openclaw symlink.

Guidance

  • Review the assertNoSymlinkPathComponents function to understand its current behavior and identify the necessary changes to support a trusted first-level ~/.openclaw symlink.
  • Consider implementing the suggested fix direction, which involves resolving the symlink with realpathSync, validating the symlink target's ownership and permissions, and continuing to reject deeper symlinks inside the resolved .openclaw tree.
  • Update the ensureDir function to call the modified assertNoSymlinkPathComponents function, ensuring that it correctly handles the trusted first-level ~/.openclaw symlink.
  • Test the changes to verify that the command succeeds for a trusted first-level ~/.openclaw symlink owned by the current user.

Example

const assertNoSymlinkPathComponents = (dir: string, homeDir: string) => {
  const stat = fs.lstatSync(dir);
  if (stat.isSymbolicLink()) {
    const resolvedDir = fs.realpathSync(dir);
    const owner = fs.statSync(resolvedDir).uid;
    const currentUser = process.getuid();
    if (owner === currentUser && !fs.accessSync(resolvedDir, fs.constants.W_OK | fs.constants.X_OK)) {
      // Allow the trusted first-level symlink
      return;
    }
  }
  // Reject deeper symlinks or untrusted symlinks
  throw new Error(`Refusing to traverse symlink in exec approvals path: ${dir}`);
};

Notes

The provided code snippet is a simplified example and may require additional modifications to fit the specific requirements of the OpenClaw project.

Recommendation

Apply the suggested fix direction to modify the assertNoSymlinkPathComponents function and update the `ensureDir

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The command should succeed for a trusted first-level ~/.openclaw symlink owned by the current user, while still rejecting deeper symlink traversal inside the approvals path.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: exec-policy still rejects symlinked ~/.openclaw after #72377 replacement for #64663 [6 pull requests, 1 participants]