Skip to content

Commit 95423d9

Browse files
committed
Harden image temp path extension handling
Reject unsafe extension fragments containing path separators or parent-directory traversal markers before composing the temporary output path. This prevents path traversal through crafted image URLs in downloadImage. Also adds a regression test covering a traversal-style URL suffix. #608 (comment)
1 parent 3c7eb9b commit 95423d9

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

packages/cli/src/imagerenderer.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,19 @@ test("downloadImage - cancels body for non-ok terminal response", async () => {
173173
globalThis.fetch = originalFetch;
174174
}
175175
});
176+
177+
test("downloadImage - rejects unsafe extension containing path traversal", async () => {
178+
const originalFetch = globalThis.fetch;
179+
globalThis.fetch =
180+
((_input: URL | RequestInfo) =>
181+
Promise.resolve(new Response(new Uint8Array([1, 2, 3])))) as typeof fetch;
182+
183+
try {
184+
const result = await downloadImage(
185+
"https://198.51.100.10/image.png/../../../../etc/passwd",
186+
);
187+
assert.equal(result, null);
188+
} finally {
189+
globalThis.fetch = originalFetch;
190+
}
191+
});

packages/cli/src/imagerenderer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ export async function downloadImage(url: string): Promise<string | null> {
132132
}
133133
const imageData = new Uint8Array(await response.arrayBuffer());
134134
const extension = new URL(targetUrl).pathname.split(".").pop() || "jpg";
135+
if (
136+
extension.includes("/") || extension.includes("\\") ||
137+
extension.includes("..")
138+
) {
139+
return null;
140+
}
135141
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "fedify"));
136142
const tempPath = path.join(tempDir, `image.${extension}`);
137143

0 commit comments

Comments
 (0)