diff options
| author | Adam Malczewski <[email protected]> | 2026-10-21 14:37:28 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-10-21 14:37:28 +0900 |
| commit | 6a2a40d64737b3cb678740c8f85027c3be0000bc (patch) | |
| tree | 316420c29b54a76def9c4e41885a682dcaa1e3e9 /src/features/markdown/ui | |
| parent | 8eefbc5287f73414df7feba6c78dc8ca73783b1d (diff) | |
| download | dispatch-web-6a2a40d64737b3cb678740c8f85027c3be0000bc.tar.gz dispatch-web-6a2a40d64737b3cb678740c8f85027c3be0000bc.zip | |
fix(review-followup-feb): block raw Markdown fetch vectors and guard preview
Diffstat (limited to 'src/features/markdown/ui')
| -rw-r--r-- | src/features/markdown/ui/markdown.test.ts | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/features/markdown/ui/markdown.test.ts b/src/features/markdown/ui/markdown.test.ts index 149bff5..b86cc0a 100644 --- a/src/features/markdown/ui/markdown.test.ts +++ b/src/features/markdown/ui/markdown.test.ts @@ -62,6 +62,25 @@ describe("Markdown", () => { ).toBeInTheDocument(); }); + it.each([ + false, + true, + ])("keeps non-image HTML inert before and after image consent (streaming=%s)", async (streaming) => { + const { container } = render(Markdown, { + props: { + text: '<div style="background:url(https://evil.example/bg)"><video poster="https://evil.example/poster" src="https://evil.example/video"></video><svg><image href="https://evil.example/svg" /></svg><input type="image" src="https://evil.example/input"><img src="https://evil.example/allowed-after-click"></div>', + streaming, + }, + }); + expect(container.querySelector("video,svg,input,[style],img")).toBeNull(); + await fireEvent.click(screen.getByRole("button", { name: "Load image from evil.example" })); + expect(container.querySelectorAll("img")).toHaveLength(1); + expect(container.querySelector("img")?.getAttribute("src")).toBe( + "https://evil.example/allowed-after-click", + ); + expect(container.querySelector("video,svg,input,[style]")).toBeNull(); + }); + it("rejects an unsafe URL in a forged placeholder", async () => { const { container } = render(Markdown, { props: { text: '<button class="remote-image" data-src="javascript:alert(1)">Load</button>' }, |
