Skip to content

fix(ui): patch XSS + add TypeScript frontend to source control - #5

Merged
Taure merged 1 commit into
mainfrom
fix/xss-ui
Apr 20, 2026
Merged

Taure merged 1 commit into
mainfrom
fix/xss-ui

Conversation

@Taure

@Taure Taure commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Two things in one PR because you can't land one without the other:

  1. Add priv/static/ to the repo. The TypeScript frontend has never been committed — git log --all -- priv/ was empty. The Dockerfile does `COPY priv ./priv`, so deploys build from whatever is in the local working tree. That's now fixed: sources, assets, package.json, tsconfig, index.html are tracked. `node_modules/` and `dist/` are gitignored (dist is rebuilt from src).

  2. XSS hardening in `ui.ts`. Three `innerHTML` template literals rendered server-controlled strings (boon name/description, vote option labels, results table cells with player ids) straight into the DOM. Any stored script in those fields would execute for every viewer. Swapped for `createElement` + `textContent` / `replaceChildren` so server strings are never parsed as HTML.

Audit item S8 from the April-3 arena security review.

Test plan

  • `npm install && npm run build` clean (28 kB bundle, 3 ms)
  • `grep innerHTML priv/static/src/*.ts` returns nothing
  • Visit play.asobi.dev, play through a match end-to-end (boon pick, vote, results) after deploy
  • Verify a crafted display name (``) renders as text, not script, in the results table

The priv/static TypeScript frontend was never committed — it lived
only in dev working trees, so the running play.asobi.dev image was
built from unversioned code. Adding it now.

Alongside, fix an XSS hazard in ui.ts: three innerHTML template
literals rendered server-controlled strings (boon name/description,
vote option labels, results table rows with player ids) directly into
the DOM. Any stored script in those fields would execute for every
viewer. Replaced with createElement + textContent / replaceChildren
so server strings are never parsed as HTML.

.gitignore now excludes priv/static/node_modules and priv/static/dist
(the latter is rebuilt from src via npm run build, no need to track).
@Taure
Taure merged commit 52b2e60 into main Apr 20, 2026
15 checks passed
@Taure
Taure deleted the fix/xss-ui branch April 20, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant