mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 10:41:25 +00:00
fix(security): restrict MEDIA path extraction to prevent LFI (#4930)
* fix(security): restrict inbound media staging to media directory * docs: update MEDIA path guidance for security restrictions - Update agent hint to warn against absolute/~ paths - Update docs example to use https:// instead of /tmp/ --------- Co-authored-by: Evan Otero <evanotero@google.com>
This commit is contained in:
@@ -248,7 +248,7 @@ export async function runPreparedReply(
|
||||
const prefixedBody = [threadStarterNote, prefixedBodyBase].filter(Boolean).join("\n\n");
|
||||
const mediaNote = buildInboundMediaNote(ctx);
|
||||
const mediaReplyHint = mediaNote
|
||||
? "To send an image back, prefer the message tool (media/path/filePath). If you must inline, use MEDIA:/path or MEDIA:https://example.com/image.jpg (spaces ok, quote if needed). Keep caption in the text body."
|
||||
? "To send an image back, prefer the message tool (media/path/filePath). If you must inline, use MEDIA:https://example.com/image.jpg (spaces ok, quote if needed) or a safe relative path like MEDIA:./image.jpg. Avoid absolute paths (MEDIA:/...) and ~ paths — they are blocked for security. Keep caption in the text body."
|
||||
: undefined;
|
||||
let prefixedCommandBody = mediaNote
|
||||
? [mediaNote, mediaReplyHint, prefixedBody ?? ""].filter(Boolean).join("\n").trim()
|
||||
|
||||
@@ -2,9 +2,11 @@ import { spawn } from "node:child_process";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { assertSandboxPath } from "../../agents/sandbox-paths.js";
|
||||
import { ensureSandboxWorkspaceForSession } from "../../agents/sandbox.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { getMediaDir } from "../../media/store.js";
|
||||
import { CONFIG_DIR } from "../../utils.js";
|
||||
import type { MsgContext, TemplateContext } from "../templating.js";
|
||||
|
||||
@@ -80,6 +82,21 @@ export async function stageSandboxMedia(params: {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Local paths must be restricted to the media directory.
|
||||
if (!ctx.MediaRemoteHost) {
|
||||
const mediaDir = getMediaDir();
|
||||
try {
|
||||
await assertSandboxPath({
|
||||
filePath: source,
|
||||
cwd: mediaDir,
|
||||
root: mediaDir,
|
||||
});
|
||||
} catch {
|
||||
logVerbose(`Blocking attempt to stage media from outside media directory: ${source}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const baseName = path.basename(source);
|
||||
if (!baseName) {
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user