Skip to content

[Bug]:LaunchD plist regeneration drops Umask — gateway writes world-readable files after update #31905

@will-build

Description

@will-build

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

  1. Add Umask key to ~/Library/LaunchAgents/ai.openclaw.gateway.plist: <key>Umask</key><integer>63</integer>
  2. Confirm it works: restart gateway, check that new files are created as 600
  3. Update OpenClaw: npm install -g openclaw@<newer-version>
  4. Check the plist: plutil -p ~/Library/LaunchAgents/ai.openclaw.gateway.plist | grep -i umask
  5. Observe: Umask key is gone
  6. Trigger any file write (e.g., edit a cron job): openclaw cron edit <id> --name "test"
  7. 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.json

Impact 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 Comment field shows v2026.2.25 even on a 2026.3.1 install, suggesting the plist template may not be versioned in sync with releases
  • openclaw.json and secrets.env are 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.umask key in openclaw.json (or just default the plist template to Umask: 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingbug:behaviorIncorrect behavior without a crash

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions