From af496ce9ca3cdf65edc9c8da5e1526329e6397d4 Mon Sep 17 00:00:00 2001 From: John Ogle Date: Sun, 19 Apr 2026 16:58:07 -0700 Subject: [PATCH] fix(openclaw): copy /app as real directory to avoid symlink escape check The OpenClaw runtime validates that resolved symlinks stay within /app/dist/extensions/. When /app was a Nix store symlink, realpath resolved to /nix/store/ which 'escaped' the boundary. Now we copy the app files into /app as a real directory in extraCommands. --- packages/openclaw-image/default.nix | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/openclaw-image/default.nix b/packages/openclaw-image/default.nix index 872a56b..4a11413 100644 --- a/packages/openclaw-image/default.nix +++ b/packages/openclaw-image/default.nix @@ -159,9 +159,6 @@ pkgs.dockerTools.buildLayeredImage { # Node user home directory nodeHome - # The openclaw application extracted from the upstream image - openclawApp - # Docker entrypoint script (in /usr/local/bin) entrypointPkg @@ -184,6 +181,10 @@ pkgs.dockerTools.buildLayeredImage { # Gitea CLI (PR workflow) pkgs.tea ]; + # NOTE: openclawApp is NOT in contents. It would create /app as a symlink + # to /nix/store/..., which breaks OpenClaw's symlink escape security check + # (resolved paths "escape" /app/dist/extensions). Instead, extraCommands + # copies the real files into /app as a proper directory. extraCommands = '' # Create /tmp with correct permissions (needed by Node.js and nix) @@ -195,6 +196,14 @@ pkgs.dockerTools.buildLayeredImage { # Create /var/empty (referenced by NSS passwd home dirs) mkdir -p var/empty + + # Copy OpenClaw app as a REAL directory (not a Nix store symlink). + # The app has a symlink escape check: resolved paths must stay within + # /app/dist/extensions/. If /app is a symlink to /nix/store/HASH/app/, + # realpath resolves to /nix/store/... which "escapes" the boundary. + rm -rf app + mkdir -p app + cp -a ${openclawApp}/app/. app/ ''; config = {