From 5863ce1f78e4ad342a4392d68b4b3ace3cb49bba Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 22 Mar 2026 10:24:46 -0700 Subject: [PATCH] fix(media): narrow default local attachment roots --- docs/start/openclaw.md | 5 +++++ src/media/local-roots.test.ts | 33 +++++++++++++++++++++++++++++++++ src/media/local-roots.ts | 1 - 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/media/local-roots.test.ts diff --git a/docs/start/openclaw.md b/docs/start/openclaw.md index 647877ad225..0c8e09c41f2 100644 --- a/docs/start/openclaw.md +++ b/docs/start/openclaw.md @@ -192,6 +192,11 @@ MEDIA:https://example.com/screenshot.png OpenClaw extracts these and sends them as media alongside the text. +For local paths, the default allowlist is intentionally narrow: the OpenClaw temp +root, the media cache, agent workspace paths, and sandbox-generated files. If you +need broader local-file attachment roots, configure an explicit channel/plugin +allowlist instead of relying on arbitrary host paths. + ## Operations checklist ```bash diff --git a/src/media/local-roots.test.ts b/src/media/local-roots.test.ts new file mode 100644 index 00000000000..196a83c496d --- /dev/null +++ b/src/media/local-roots.test.ts @@ -0,0 +1,33 @@ +import path from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { getAgentScopedMediaLocalRoots, getDefaultMediaLocalRoots } from "./local-roots.js"; + +describe("local media roots", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + it("keeps temp, media cache, and workspace roots by default", () => { + const stateDir = path.join("/tmp", "openclaw-media-roots-state"); + vi.stubEnv("OPENCLAW_STATE_DIR", stateDir); + + const roots = getDefaultMediaLocalRoots(); + + expect(roots).toContain(path.join(stateDir, "media")); + expect(roots).toContain(path.join(stateDir, "workspace")); + expect(roots).toContain(path.join(stateDir, "sandboxes")); + expect(roots).not.toContain(path.join(stateDir, "agents")); + expect(roots.length).toBeGreaterThanOrEqual(3); + }); + + it("adds the active agent workspace without re-opening broad agent state roots", () => { + const stateDir = path.join("/tmp", "openclaw-agent-media-roots-state"); + vi.stubEnv("OPENCLAW_STATE_DIR", stateDir); + + const roots = getAgentScopedMediaLocalRoots({}, "ops"); + + expect(roots).toContain(path.join(stateDir, "workspace-ops")); + expect(roots).toContain(path.join(stateDir, "sandboxes")); + expect(roots).not.toContain(path.join(stateDir, "agents")); + }); +}); diff --git a/src/media/local-roots.ts b/src/media/local-roots.ts index 51476200ca1..d44ed511c19 100644 --- a/src/media/local-roots.ts +++ b/src/media/local-roots.ts @@ -26,7 +26,6 @@ function buildMediaLocalRoots( return [ preferredTmpDir, path.join(resolvedStateDir, "media"), - path.join(resolvedStateDir, "agents"), path.join(resolvedStateDir, "workspace"), path.join(resolvedStateDir, "sandboxes"), ];