Skip to content

Bug: openclaw skills install changes /tmp permissions from 1777 to 0700 #101224

Description

@ch3ch2cho2021

Bug: openclaw skills install changes /tmp directory permissions from 1777 to 0700

Summary

When OpenClaw installs or updates skills via the clawhub skill installation mechanism, it creates temporary working directories under /tmp using fs.mkdir with mode: 0o700. Due to Node.js's fs.mkdir({ recursive: true }) behavior, this inadvertently changes the permissions of the /tmp directory itself from 1777 (sticky, world-writable) to 0700 (owner-only), breaking all other services that depend on /tmp.

Environment

  • OS: Linux 6.11.0+ aarch64 (ARM64)
  • Node.js: v24.17.0
  • OpenClaw: 2026.6.11 (e085fa1)
  • /tmp: on root filesystem (not a separate tmpfs mount)

Reproduction

  1. Ensure /tmp has correct permissions: stat -c '%a' /tmp1777
  2. Trigger a skill installation/update (e.g., via openclaw skills install <skill> or a cron job that calls the skills update flow)
  3. Check /tmp permissions again: stat -c '%a' /tmp0700

Root Cause

The openclaw-skills process creates temp directories like /tmp/openclaw-clawhub-skill-<random> and /tmp/openclaw-skill-clawhub-<uuid>-<random> using Node.js fs.mkdir(path, { recursive: true, mode: 0o700 }).

On Node.js, when recursive: true is used with a mode option, the recursive implementation may call chmod on existing parent directories in the path. This is a known Node.js behavior. Since /tmp is the parent of the temp directory being created, /tmp itself gets chmod'd to 0700.

Evidence (auditd logs)

An audit watch (-w /tmp -p a -k tmp_perm_change) captured the exact sequence:

Step 1: /tmp is 041777 (directory, sticky, 1777):

type=PATH msg=audit(1783281709.632:29259): item=0 name="/tmp" inode=6291457 dev=08:02 mode=041777 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=SYSCALL msg=audit(1783281709.632:29259): arch=c00000b7 syscall=53 success=yes exit=0 a0=ffffffffffffff9c a1=457330f0 a2=1c0 a3=0 items=1 ppid=2461804 pid=2461811 comm="libuv-worker" exe="/usr/bin/node" proctitle="openclaw-skills"

Step 2: A temp dir is created under /tmp with mode 0700:

type=PATH msg=audit(1783281709.632:29260): item=0 name="/tmp/openclaw-clawhub-skill-PddW4r" inode=6296121 dev=08:02 mode=040700
type=SYSCALL msg=audit(1783281709.632:29260): syscall=53 a2=1c0 proctitle="openclaw-skills"

Step 3: /tmp is now 040700 (directory, 0700) — permissions changed!:

type=PATH msg=audit(1783281709.632:29261): item=0 name="/tmp" inode=6291457 dev=08:02 mode=040700 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=SYSCALL msg=audit(1783281709.632:29261): syscall=53 a2=1c0 proctitle="openclaw-skills"

The syscall number 53 on ARM64 is mkdirat. The a2=0x1c0 = 0o700 in octal. In the span of 1 millisecond, /tmp went from 041777 to 040700.

This was reproducible across multiple days (observed on 2026-07-06 04:01 and 2026-07-07 04:00).

Impact

  • Any service relying on /tmp being world-writable breaks (MySQL, PHP-FPM, bt-monitor, system tools, etc.)
  • Services may fail silently or with confusing permission-denied errors
  • The issue is recurring if skill updates run on a schedule (e.g., daily cron)
  • Hard to diagnose — the permission change happens silently with no log output

Suggested Fix

  1. Use os.tmpdir() or a subdirectory that doesn't clobber /tmp itself — e.g., create /tmp/openclaw-skill-staging/ first (without recursive), then create temp dirs inside it.

  2. Or don't pass mode to fs.mkdir when creating dirs under /tmp — the default mode (0o777 & ~umask) is fine for temp staging dirs, and won't trigger the recursive chmod on /tmp.

  3. Or explicitly restore /tmp permissions after skill installation completes: fs.chmod('/tmp', 0o1777).

Workaround

Users can add a cron job to restore /tmp after skill updates:

# Fix /tmp permissions after openclaw skill updates
5 4 * * * chmod 1777 /tmp

Or rewrite the update cron task to only check for updates (not install), and install manually.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Emergency: data loss, security bypass, crash loop, or unusable core runtime.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:crash-loopCrash, hang, restart loop, or process-level availability failure.impact:ux-release-blockerA non-technical user is blocked without terminal, logs, config, or support.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.no-staleExclude from stale automation

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions