-
-
Notifications
You must be signed in to change notification settings - Fork 52.6k
Description
Bug type
Behavior bug (incorrect output/state without crash)
Summary
Summary: When OpenClaw updates via npm install -g openclaw, the LaunchD plist is regenerated from scratch, dropping any custom keys (including Umask). The gateway then runs with the system default umask (022), causing all new config and state files to be created with 644 permissions (world-readable) instead of 600.
What's broken: npm updates overwrite the LaunchD plist without preserving custom security settings, leaving gateway-written files world-readable until the next security audit runs.
Steps to reproduce
- Add
Umaskkey to~/Library/LaunchAgents/ai.openclaw.gateway.plist:<key>Umask</key><integer>63</integer> - Confirm it works: restart gateway, check that new files are created as 600
- Update OpenClaw:
npm install -g openclaw@<newer-version> - Check the plist:
plutil -p ~/Library/LaunchAgents/ai.openclaw.gateway.plist | grep -i umask - Observe: Umask key is gone
- Trigger any file write (e.g., edit a cron job):
openclaw cron edit <id> --name "test" - Check permissions:
ls -la ~/.openclaw/cron/jobs.json
Expected behavior
Gateway-written files should always be owner-only (600). Either the plist template should include a restrictive umask by default, or a gateway.umask config option in openclaw.json should be respected during plist generation.
Actual behavior
After update, cron/jobs.json and other state files are created as 644 (owner read-write, group/world readable). The Umask key added to the plist is silently removed.
OpenClaw version
2026.3.1
Operating system
15 Sequoia (Apple Silicon, arm64)
Install method
npm global (npm install -g openclaw), LaunchD service
Logs, screenshots, and evidence
# Before update — umask set, files correct
$ plutil -p ~/Library/LaunchAgents/ai.openclaw.gateway.plist | grep Umask
"Umask" => 63
# After npm update — umask gone
$ plutil -p ~/Library/LaunchAgents/ai.openclaw.gateway.plist | grep Umask
(no output)
# Files written after update
$ ls -la ~/.openclaw/cron/jobs.json
-rw-r--r-- 1 myuser staff 11140 Mar 2 08:55 jobs.json
# After manual fix
$ ls -la ~/.openclaw/cron/jobs.json
-rw------- 1 myuser staff 11140 Mar 2 08:55 jobs.jsonImpact and severity
Medium. On a single-user machine the risk is low, but on any shared system, sensitive data (API tokens in session state, cron job configs, delivery targets) could be readable by other local users. The daily security audit catches and fixes permissions, but there's a window of exposure between update and next audit. The openclaw security audit command correctly flags loose permissions but doesn't prevent them from being created in the first place.
Additional information
- The plist
Commentfield showsv2026.2.25even on a 2026.3.1 install, suggesting the plist template may not be versioned in sync with releases openclaw.jsonandsecrets.envare explicitly checked for 600 by the security audit, but transient state files (cron/jobs.json, session files) are only caught on the next audit pass- Suggested fix: a
gateway.umaskkey inopenclaw.json(or just default the plist template toUmask: 63) so the setting is config-driven and survives updates - Current workaround: post-update hardening script that re-adds the Umask key and chmods state files, triggered by a cron-based release checker