Files
Moltbot/src/media/parse.test.ts
Evan Otero c67df653b6 fix(security): restrict local path extraction in media parser to prevent LFI (#4880)
* Media: restrict local path extraction to prevent LFI

* Lint: remove unused variable hasValidMediaOnLine
2026-01-31 03:44:11 +01:00

63 lines
2.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { splitMediaFromOutput } from "./parse.js";
describe("splitMediaFromOutput", () => {
it("detects audio_as_voice tag and strips it", () => {
const result = splitMediaFromOutput("Hello [[audio_as_voice]] world");
expect(result.audioAsVoice).toBe(true);
expect(result.text).toBe("Hello world");
});
it("rejects absolute media paths to prevent LFI", () => {
const result = splitMediaFromOutput("MEDIA:/Users/pete/My File.png");
expect(result.mediaUrls).toBeUndefined();
expect(result.text).toBe("MEDIA:/Users/pete/My File.png");
});
it("rejects quoted absolute media paths to prevent LFI", () => {
const result = splitMediaFromOutput('MEDIA:"/Users/pete/My File.png"');
expect(result.mediaUrls).toBeUndefined();
expect(result.text).toBe('MEDIA:"/Users/pete/My File.png"');
});
it("rejects tilde media paths to prevent LFI", () => {
const result = splitMediaFromOutput("MEDIA:~/Pictures/My File.png");
expect(result.mediaUrls).toBeUndefined();
expect(result.text).toBe("MEDIA:~/Pictures/My File.png");
});
it("rejects directory traversal media paths to prevent LFI", () => {
const result = splitMediaFromOutput("MEDIA:../../etc/passwd");
expect(result.mediaUrls).toBeUndefined();
expect(result.text).toBe("MEDIA:../../etc/passwd");
});
it("captures safe relative media paths", () => {
const result = splitMediaFromOutput("MEDIA:./screenshots/image.png");
expect(result.mediaUrls).toEqual(["./screenshots/image.png"]);
expect(result.text).toBe("");
});
it("keeps audio_as_voice detection stable across calls", () => {
const input = "Hello [[audio_as_voice]]";
const first = splitMediaFromOutput(input);
const second = splitMediaFromOutput(input);
expect(first.audioAsVoice).toBe(true);
expect(second.audioAsVoice).toBe(true);
});
it("keeps MEDIA mentions in prose", () => {
const input = "The MEDIA: tag fails to deliver";
const result = splitMediaFromOutput(input);
expect(result.mediaUrls).toBeUndefined();
expect(result.text).toBe(input);
});
it("parses MEDIA tags with leading whitespace", () => {
const result = splitMediaFromOutput(" MEDIA:./screenshot.png");
expect(result.mediaUrls).toEqual(["./screenshot.png"]);
expect(result.text).toBe("");
});
});