From 48206b56272454a6c60329e542f5560c83afd2ba Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Tue, 14 Apr 2026 16:50:51 -0400 Subject: [PATCH] fix: fail closed on sandbox media mapping errors --- .../reply/reply-media-paths.test.ts | 22 +++++++++++++++++++ src/auto-reply/reply/reply-media-paths.ts | 8 +------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/auto-reply/reply/reply-media-paths.test.ts b/src/auto-reply/reply/reply-media-paths.test.ts index 05b0cbb5621..d7aca2428fa 100644 --- a/src/auto-reply/reply/reply-media-paths.test.ts +++ b/src/auto-reply/reply/reply-media-paths.test.ts @@ -162,6 +162,28 @@ describe("createReplyMediaPathNormalizer", () => { expect(resolveOutboundAttachmentFromUrl).not.toHaveBeenCalled(); }); + it("drops absolute host-local media paths when sandbox mapping fails", async () => { + ensureSandboxWorkspaceForSession.mockResolvedValue({ + workspaceDir: "/tmp/sandboxes/session-1", + containerWorkdir: "/workspace", + }); + const normalize = createReplyMediaPathNormalizer({ + cfg: { tools: { fs: { workspaceOnly: false } } }, + sessionKey: "session-key", + workspaceDir: "/tmp/agent-workspace", + }); + + const result = await normalize({ + mediaUrls: ["/Users/peter/Documents/report.pdf"], + }); + + expect(result).toMatchObject({ + mediaUrl: undefined, + mediaUrls: undefined, + }); + expect(resolveOutboundAttachmentFromUrl).not.toHaveBeenCalled(); + }); + it("stages absolute workspace media paths so the PR scenario now works", async () => { const absolutePath = "/Users/peter/.openclaw/workspace/exports/images/chart.png"; const normalize = createReplyMediaPathNormalizer({ diff --git a/src/auto-reply/reply/reply-media-paths.ts b/src/auto-reply/reply/reply-media-paths.ts index 43de02ac6a6..2f59a8b37e4 100644 --- a/src/auto-reply/reply/reply-media-paths.ts +++ b/src/auto-reply/reply/reply-media-paths.ts @@ -187,19 +187,13 @@ export function createReplyMediaPathNormalizer(params: { sandboxRoot, }); } catch (err) { - if (!isLikelyLocalMediaSource(media)) { - throw err; - } if (FILE_URL_RE.test(media)) { throw new Error( "Host-local MEDIA file URLs are blocked in normal replies. Use a safe path or the message tool.", { cause: err }, ); } - if (isRelativeLocalMedia) { - return await persistLocalReplyMedia(resolveWorkspaceRelativeMedia(media)); - } - return await persistLocalReplyMedia(media); + throw err; } return await persistLocalReplyMedia(sandboxResolvedMedia); }