diff --git a/ui/src/ui/chat/grouped-render.ts b/ui/src/ui/chat/grouped-render.ts
index d4f2be30e46..adc5df0da58 100644
--- a/ui/src/ui/chat/grouped-render.ts
+++ b/ui/src/ui/chat/grouped-render.ts
@@ -670,9 +670,13 @@ function renderMessageImages(
return html`
${images.map((img) => {
+ const isLocalImage = isLocalAssistantAttachmentSource(img.url);
const canProxyLocalImage =
- isLocalAssistantAttachmentSource(img.url) &&
+ isLocalImage &&
isLocalAttachmentPreviewAllowed(img.url, opts?.localMediaPreviewRoots ?? []);
+ if (isLocalImage && !canProxyLocalImage) {
+ return nothing;
+ }
const imageUrl = canProxyLocalImage
? buildAssistantAttachmentUrl(img.url, opts?.basePath, opts?.authToken)
: img.url;
diff --git a/ui/src/ui/views/chat.test.ts b/ui/src/ui/views/chat.test.ts
index aedc309faf9..5c555697762 100644
--- a/ui/src/ui/views/chat.test.ts
+++ b/ui/src/ui/views/chat.test.ts
@@ -974,6 +974,31 @@ describe("chat view", () => {
);
});
+ it("does not render blocked local transcript image paths", () => {
+ const container = document.createElement("div");
+
+ renderGroupedMessage(
+ container,
+ {
+ id: "user-history-image-blocked",
+ role: "user",
+ content: "",
+ MediaPath: "/Users/test/Documents/private.png",
+ MediaType: "image/png",
+ timestamp: Date.now(),
+ },
+ "user",
+ {
+ showToolCalls: false,
+ basePath: "/openclaw",
+ assistantAttachmentAuthToken: "session-token",
+ localMediaPreviewRoots: ["/tmp/openclaw"],
+ },
+ );
+
+ expect(container.querySelector(".chat-message-image")).toBeNull();
+ });
+
it("skips non-image transcript media paths after history reload", () => {
const container = document.createElement("div");