← Back to PRs

#19191: fix(security): harden cron file permissions to 0o600

by Kropiunig open 2026-02-17 14:14 View on GitHub →
size: S
## Summary Fixes #18866 The cron subsystem creates `jobs.json`, `jobs.json.bak`, and run log files (`runs/*.jsonl`) with default permissions (0o644 / world-readable). On multi-user systems, this exposes scheduled task configurations, session keys, and model usage metadata to other local users. As confirmed by [@fridayjoshi in the issue thread](https://github.com/openclaw/openclaw/issues/18866#issuecomment-3904082971), `fixSecurityFootguns` (behind `openclaw doctor --fix` / `openclaw security audit --fix`) correctly hardens the config file and agent state, but **does not cover the cron directory at all** — leaving `~/.openclaw/cron/` and its contents at 0o664/0o775 even after a full security fix pass. ## Root cause Two gaps in the permission hardening story: 1. **Write-time**: `saveCronStore()` and `appendCronRunLog()` call `fs.writeFile` / `fs.appendFile` / `fs.mkdir` without specifying `mode`, so newly created cron files inherit the process umask (typically 0o022 → resulting in 0o644 files and 0o755 directories). 2. **Fix-time**: `fixSecurityFootguns()` iterates over credentials, agent state, sessions, and transcripts — but has no coverage for `cron/`, `cron/jobs.json`, `cron/jobs.json.bak`, or `cron/runs/*.jsonl`. ## Changes ### Write-time hardening - **`src/cron/store.ts`** — `saveCronStore()`: set `mode: 0o600` on `writeFile`, `chmod(0o600)` on the backup copy, `mode: 0o700` on `mkdir` - **`src/cron/run-log.ts`** — `appendCronRunLog()` and `pruneIfNeeded()`: set `mode: 0o600` on `writeFile` / `appendFile`, `mode: 0o700` on `mkdir` ### Retroactive fix via `doctor --fix` / `security audit --fix` - **`src/security/fix.ts`** — Add `chmodCronState()` to `fixSecurityFootguns()`, covering: - `cron/` directory → 0o700 - `cron/jobs.json` → 0o600 - `cron/jobs.json.bak` → 0o600 - `cron/runs/` directory → 0o700 - `cron/runs/*.jsonl` → 0o600 ### Tests - **`src/cron/store.test.ts`** — Verify `saveCronStore` creates files at 0o600 and directory at 0o700 - **`src/security/fix.test.ts`** — Verify `fixSecurityFootguns` hardens existing cron files from 0o644 → 0o600 ## Test plan - [x] `src/cron/store.test.ts` — 4 tests pass (including new permissions test) - [x] `src/cron/run-log.test.ts` — 3 tests pass - [x] `src/security/fix.test.ts` — 6 tests pass (including new cron coverage test) - [x] oxlint passes on all changed files <!-- greptile_comment --> <h3>Greptile Summary</h3> Hardens cron file permissions from world-readable (0o644) to owner-only (0o600) to prevent exposure of scheduled task configurations, session keys, and model usage metadata on multi-user systems. **Key changes:** - `saveCronStore()` now creates `jobs.json` with `0o600` and directories with `0o700` - `appendCronRunLog()` creates run log files (`runs/*.jsonl`) with `0o600` - `fixSecurityFootguns()` now retroactively hardens existing cron files via new `chmodCronState()` function The implementation follows the repository's established security patterns and includes comprehensive test coverage for both write-time and fix-time hardening. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with no identified risks - The implementation correctly addresses the security vulnerability with appropriate permissions (0o600 for files, 0o700 for directories), includes comprehensive test coverage for both new file creation and retroactive hardening, follows established codebase patterns, and has no edge cases or security concerns - No files require special attention <sub>Last reviewed commit: 3ac6853</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs