mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-20 09:31:54 -06:00
0d7fb8eb39
* refactor(fs): unify exclusive file publication * fix(fs): fence stale lock reclamation * refactor(fs): bound wiki scans and secret reads * chore(fs): finalize fs-safe 0.5 compatibility * fix(fs): preserve publication ownership and legacy mode * fix(fs): fail closed on unverifiable lock owners * fix(fs): preserve concurrent backup publications * refactor(fs): preserve ambiguous backup outputs * fix(fs): preserve mixed-version lock coordination * refactor(file-transfer): adopt fs-safe archive extraction * refactor(fs): add bounded walk and secret seams * refactor(auth): replace proper-lockfile with fs-safe * fix(fs): honor Windows mode override casing * refactor(snapshot): adopt fs-safe publication * refactor(memory-wiki): adopt prunable root walks * refactor(fleet): adopt bounded archive restore * fix(fs): preserve post-publication ownership receipts * refactor(fs): harvest final fs-safe primitives * style(fs): clean harvest lint * chore(plugin-sdk): refresh move helper API baseline * refactor(snapshot): adopt native Windows ACL facts * refactor(fs): adopt hardened atomic outputs * fix(fs): scope lock reentrancy to logical owners * chore(config): lower env var count budget * fix(deps): adopt published fs-safe 0.5.0 * fix(ci): align SDK surface ratchets * fix(ci): regenerate SDK API baseline after rebase * fix(fs): preserve owner-scoped file lock nesting * fix(ci): refresh SDK API baseline for file locks * fix(fs): separate SQLite and file lock reentrancy * fix(imessage): bound pinned attachment reads * fix(agents): narrow session-key lock options * fix(fs): preserve fs-safe 0.5 compatibility contracts * fix(windows): retain private SQLite directory owner * refactor(sqlite): centralize exclusive coordinator * refactor(snapshot): isolate Windows ACL policy * fix(windows): retain snapshot ACL inspector * chore(config): realign env budget after rebase * test(agents): accept canonical sandbox escape error * docs(changelog): defer fs-safe release note
74 lines
4.4 KiB
Markdown
74 lines
4.4 KiB
Markdown
---
|
|
summary: "How OpenClaw handles local file access safely, and why optional fs-safe native acceleration is off by default"
|
|
read_when:
|
|
- Changing file access, archive extraction, workspace storage, or plugin filesystem helpers
|
|
title: "Secure file operations"
|
|
---
|
|
|
|
OpenClaw uses [`@openclaw/fs-safe`](https://github.com/openclaw/fs-safe) for security-sensitive local file operations: root-bounded reads/writes, atomic replacement, archive extraction, temp workspaces, JSON state, and secret-file handling.
|
|
|
|
It is a **library guardrail** for trusted OpenClaw code that receives untrusted path names, not a sandbox. Host filesystem permissions, OS users, containers, and the agent/tool policy still define the real blast radius.
|
|
|
|
## Default: JavaScript fallback
|
|
|
|
OpenClaw sets fs-safe's optional native helper to **off** by default:
|
|
|
|
- native platform packages are optional and may be absent from minimal installs;
|
|
- the guarded JavaScript paths support OpenClaw's normal filesystem operations;
|
|
- disabling native loading keeps runtime behavior deterministic across desktop, Docker, CI, and bundled-app environments.
|
|
|
|
OpenClaw only changes the _default_. An explicit setting always wins:
|
|
|
|
```bash
|
|
# Default OpenClaw behavior: guarded JavaScript fs-safe paths.
|
|
OPENCLAW_FS_SAFE_NATIVE_MODE=off
|
|
|
|
# Prefer native primitives when the platform package is installed.
|
|
OPENCLAW_FS_SAFE_NATIVE_MODE=auto
|
|
|
|
# Fail closed when an operation needs native support and the binding is unavailable.
|
|
OPENCLAW_FS_SAFE_NATIVE_MODE=require
|
|
```
|
|
|
|
The generic fs-safe environment name also works: `FS_SAFE_NATIVE_MODE`.
|
|
|
|
fs-safe 0.5 temporarily maps the retired `FS_SAFE_PYTHON_MODE` and `OPENCLAW_FS_SAFE_PYTHON_MODE` values to native modes and emits a deprecation warning. Migrate those names before fs-safe 0.6; Python interpreter path settings are no longer used.
|
|
|
|
Use `require` (not `auto`) when native primitives are part of your security posture. `auto` uses the guarded JavaScript implementation when the platform binding is unavailable.
|
|
|
|
## What stays protected without native acceleration
|
|
|
|
With the helper off, OpenClaw still gets fs-safe's Node-only guardrails:
|
|
|
|
- rejects relative-path escapes (`..`), absolute paths, and path separators where only bare names are allowed;
|
|
- resolves operations through a trusted root handle instead of ad-hoc `path.resolve(...).startsWith(...)` checks;
|
|
- refuses symlink and hardlink patterns on APIs that require that policy;
|
|
- opens files with identity checks where the API returns or consumes file contents;
|
|
- writes state/config files via atomic sibling-temp + rename;
|
|
- enforces byte limits for reads and archive extraction;
|
|
- applies private file modes for secrets and state files where the API requires them.
|
|
|
|
This covers OpenClaw's normal threat model: trusted gateway code handling untrusted model/plugin/channel path input inside a single trusted operator boundary.
|
|
|
|
## What native acceleration adds
|
|
|
|
The optional platform package provides policy-free filesystem primitives used by fs-safe for create-only writes, guarded hard-link publication, asynchronous sidecar creation, and explicit no-replace rename publication. Linux uses `openat2` and `renameat2`; macOS uses descriptor-relative component checks and `renameatx_np`; Windows uses handle-relative operations and replacement-disabled rename.
|
|
|
|
The TypeScript layer still owns policy, validation, retries, cleanup, and fallback decisions. Native support narrows filesystem race windows; it does not turn fs-safe into a sandbox.
|
|
|
|
If your deployment requires those native primitives, install the matching optional platform package and set:
|
|
|
|
```bash
|
|
OPENCLAW_FS_SAFE_NATIVE_MODE=require
|
|
```
|
|
|
|
## Plugin and core guidance
|
|
|
|
- Plugin-facing file access should go through `openclaw/plugin-sdk/*` helpers, not raw `fs`, when a path comes from a message, model output, config, or plugin input.
|
|
- Core code should use the fs-safe wrappers under `src/infra/*` so OpenClaw's process policy applies consistently.
|
|
- Archive extraction should use the fs-safe archive helpers with explicit size, entry-count, link, and destination limits.
|
|
- Secrets should use OpenClaw secret helpers or fs-safe secret/private-state helpers; do not hand-roll mode checks around `fs.writeFile`.
|
|
- For hostile local-user isolation, do not rely on fs-safe alone. Run separate gateways under separate OS users/hosts, or use sandboxing.
|
|
|
|
Related: [Security](/gateway/security), [Sandboxing](/gateway/sandboxing), [Exec approvals](/tools/exec-approvals), [Secrets](/gateway/secrets).
|