#11408: Security: resolve symlink target permissions in safeStat; skip doctor config warning for symlinks (#11307)
commands
stale
Cluster:
Session File Path Management
## Summary
Fixes #11307
Also addresses the `openclaw status` false positive reported in the [issue comment](https://github.com/openclaw/openclaw/issues/11307#issuecomment-2841078291) by @fredcy.
## Problem
`openclaw doctor` and `openclaw status` warn that config file is group/world readable when using nix-openclaw (home-manager). This is a false positive because:
1. The config is a nix-managed **symlink**, and symlinks always show permissions as `0o777` regardless of target permissions
2. The target file lives in `/nix/store` which is **read-only** — `chmod` would fail
3. The containing `~/.openclaw` directory is mode `700`, protecting all files within
## Root Cause
- `safeStat()` in `audit-fs.ts` uses `lstat()` which returns the symlink's own mode (`0o777`), not the target's real permissions\n- `doctor-state-integrity.ts` checks `stat.mode & 0o077` against the symlink mode, triggering a false warning\n\n## Fix (two layers)\n\n### 1. `safeStat()` — resolve symlink target permissions\n\nWhen the path is a symlink, follow it with `fs.stat()` to get the **target's real permissions**. This fixes all callers (doctor, status, security audit) at once. Broken symlinks are handled gracefully with `isSymlink: true` preserved in the error path.\n\n### 2. `doctor-state-integrity.ts` — skip warning for read-only symlink targets\n\nFor symlinks whose target is **not writable** (e.g. `/nix/store`), skip the permission warning entirely — `chmod` would fail and the directory-level protection is sufficient.\n\nFor symlinks to **writable** world-readable targets, the warning is **still shown** — this is a real security concern.\n\n## Model resolution priority\n\n| Scenario | Warning? | Action |\n|---|---|---|\n| Regular file, mode 644 | ✅ Yes | Offer chmod 600 |\n| Symlink → read-only target (nix store) | ❌ No | Skip (chmod would fail, dir protects) |\n| Symlink → writable 644 target | ✅ Yes | Offer chmod 600 |\n| Broken symlink | ❌ No | Error logged |\n\n## Changes\n- `src/security/audit-fs.ts`: `safeStat()` follows symlinks to get target permissions (+28 lines)\n- `src/commands/doctor-state-integrity.ts`: Skip warning for read-only symlink targets (+14 lines)\n- `src/security/audit-fs.symlink.test.ts`: 5 tests covering symlink resolution, broken symlinks, and `inspectPathPermissions`\n- `CHANGELOG.md`: Add entry\n\n## Testing\n\n- 5 symlink-specific tests pass (`audit-fs.symlink.test.ts`)\n- 43 doctor tests pass (`pnpm vitest run src/commands/doctor`)\n- `pnpm lint` passes with 0 errors\n\n## vs PR #11458\n\nBoth PRs fix the same issue. Key differences:\n- This PR fixes **both** `safeStat` (affects all callers including `openclaw status`) **and** `doctor`\n- This PR distinguishes read-only vs writable symlink targets (same approach as #11458)\n- #11458 only fixes `doctor`, not `safeStat`/`status`
Most Similar PRs
#16957: fix(doctor): skip false positive permission warnings for Nix store ...
by soumikbhatta · 2026-02-15
85.1%
#7007: Fix security audit false-positive for symlinked state dir
by MohammadErfan-Jabbari · 2026-02-02
77.0%
#9154: fix(doctor): resolve symlinks before comparing state directories
by gavinbmoore · 2026-02-04
76.8%
#23432: Doctor: prevent permissive secret file modes during --fix
by bmendonca3 · 2026-02-22
71.7%
#18593: fix: resolve symlinks in session path validation (#18553)
by EpaL · 2026-02-16
70.9%
#23308: fix(browser): accept upload paths that traverse symlinked tmp dirs
by SidQin-cyber · 2026-02-22
68.7%
#21245: fix(plugins): harden symlinked extension discovery
by victorGPT · 2026-02-19
67.9%
#19032: fix(security): tighten permissions for cron/, browser/, settings/ i...
by moxunjinmu · 2026-02-17
66.6%
#18961: fix: detect pnpm package manager in openclaw update
by norci · 2026-02-17
66.6%
#23620: fix(memory): follow symlinks in memory indexer, reader, and watcher
by Diaspar4u · 2026-02-22
66.4%