From 7f1da24a0e7082e39b461695f91debda913ec3ee Mon Sep 17 00:00:00 2001 From: vagdotdev Date: Tue, 30 Jun 2026 12:12:16 +0530 Subject: [PATCH] fix: escape admin event page values --- routes/admin/events/list.ts | 23 ++++++++++++++------- tests/routes/admin-events-page.test.ts | 28 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 tests/routes/admin-events-page.test.ts diff --git a/routes/admin/events/list.ts b/routes/admin/events/list.ts index e0c9c1d..18592f3 100644 --- a/routes/admin/events/list.ts +++ b/routes/admin/events/list.ts @@ -1,6 +1,15 @@ import { withRouteSpec } from "lib/middleware/with-winter-spec" import { z } from "zod" +function escapeHtml(value: string): string { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'") +} + export default withRouteSpec({ methods: ["GET"], jsonResponse: z.any(), @@ -34,13 +43,13 @@ export default withRouteSpec({ .map( ({ event_type, event_id, created_at, ...rest }) => ` - ${event_type} - ${new Date( - created_at, - ).toLocaleString()} - ${JSON.stringify(rest) - .slice(1, -1) - .replace(/"([^"]+)":/g, "$1:")} + ${escapeHtml(event_type)} + ${escapeHtml(new Date(created_at).toLocaleString())} + ${escapeHtml( + JSON.stringify(rest) + .slice(1, -1) + .replace(/"([^"]+)":/g, "$1:"), + )} `, ) diff --git a/tests/routes/admin-events-page.test.ts b/tests/routes/admin-events-page.test.ts new file mode 100644 index 0000000..8c6a2e4 --- /dev/null +++ b/tests/routes/admin-events-page.test.ts @@ -0,0 +1,28 @@ +import { test, expect } from "bun:test" +import { getTestServer } from "tests/fixtures/get-test-server" + +test("admin events page escapes untrusted event values", async () => { + const { axios } = await getTestServer() + + await axios.post("/events/create", { + event_type: 'USER_LOGIN">', + file_path: '/">.txt', + initiator: '', + }) + + const res = await axios.get("/admin/events/list") + const html = res.data as string + + expect(html).toContain( + "USER_LOGIN"><script>alert(1)</script>", + ) + expect(html).toContain( + "file_path:"/\\"><img src=x onerror=\\"alert(2)\\">.txt"", + ) + expect(html).toContain( + "initiator:"<svg onload=\\"alert(3)\\">"", + ) + expect(html).not.toContain("") + expect(html).not.toContain('') + expect(html).not.toContain('') +})