mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 23:38:27 +00:00
fix(media): block symlink traversal
This commit is contained in:
@@ -17,24 +17,31 @@ export function attachMediaRoutes(
|
||||
|
||||
app.get("/media/:id", async (req, res) => {
|
||||
const id = req.params.id;
|
||||
const file = path.resolve(mediaDir, id);
|
||||
const mediaRoot = path.resolve(mediaDir) + path.sep;
|
||||
if (!file.startsWith(mediaRoot)) {
|
||||
res.status(400).send("invalid path");
|
||||
return;
|
||||
}
|
||||
const mediaRoot = (await fs.realpath(mediaDir)) + path.sep;
|
||||
const file = path.resolve(mediaRoot, id);
|
||||
|
||||
try {
|
||||
const stat = await fs.stat(file);
|
||||
const lstat = await fs.lstat(file);
|
||||
if (lstat.isSymbolicLink()) {
|
||||
res.status(400).send("invalid path");
|
||||
return;
|
||||
}
|
||||
const realPath = await fs.realpath(file);
|
||||
if (!realPath.startsWith(mediaRoot)) {
|
||||
res.status(400).send("invalid path");
|
||||
return;
|
||||
}
|
||||
const stat = await fs.stat(realPath);
|
||||
if (Date.now() - stat.mtimeMs > ttlMs) {
|
||||
await fs.rm(file).catch(() => {});
|
||||
await fs.rm(realPath).catch(() => {});
|
||||
res.status(410).send("expired");
|
||||
return;
|
||||
}
|
||||
res.sendFile(file);
|
||||
res.sendFile(realPath);
|
||||
// best-effort single-use cleanup after response ends
|
||||
res.on("finish", () => {
|
||||
setTimeout(() => {
|
||||
fs.rm(file).catch(() => {});
|
||||
fs.rm(realPath).catch(() => {});
|
||||
}, 500);
|
||||
});
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user