Skip to content

fix(frontend): escape HTML before markdown rendering in Kaizen mandate preview#17

Open
wstlima wants to merge 1 commit into
AlphaHorizon-AI:mainfrom
wstlima:fix/xss-kaizen-mandate-preview
Open

fix(frontend): escape HTML before markdown rendering in Kaizen mandate preview#17
wstlima wants to merge 1 commit into
AlphaHorizon-AI:mainfrom
wstlima:fix/xss-kaizen-mandate-preview

Conversation

@wstlima

@wstlima wstlima commented Jul 10, 2026

Copy link
Copy Markdown

Fixes #8

Summary

Kaizen.tsx's renderMarkdown() (used for the agent "mandate" preview via dangerouslySetInnerHTML) applies regex-based markdown substitutions directly to raw user-editable text, without escaping HTML first. The mandate field is user-editable free text (the agent's behavioral directive) and is rendered as HTML whenever "Preview" is toggled.

Flagged by CodeQL (js/xss-through-dom): DOM text reinterpreted as HTML without escaping meta-characters.

Impact

Stored XSS. Any mandate value containing raw HTML/script (e.g. <img src=x onerror=alert(1)>), whether entered directly in the UI or written via the API by an integration/compromised agent, executes in the browser of anyone who opens the Preview tab for that mandate.

Fix

Escape HTML special characters (&, <, >, ", ') before applying the markdown-to-HTML regex substitutions, so any embedded tags render as literal text instead of being interpreted as markup. Preserves all existing markdown formatting since escaping runs before those regexes and none of them rely on raw angle brackets from the input.

No backend change — purely client-side rendering fix.

Test plan

  • npx tsc --noEmit passes
  • Existing markdown formatting (headers, bold, italic, lists, hr, line breaks) unaffected

…e preview

Kaizen.tsx's renderMarkdown() (used for the agent "mandate" preview via
dangerouslySetInnerHTML at line 357) applies regex-based markdown
substitutions directly to raw user-editable text, without escaping
HTML first. The mandate field is user-editable free text (the agent's
behavioral directive, edited in the same page) and is rendered as
HTML whenever "Preview" is toggled.

Flagged by CodeQL (js/xss-through-dom): DOM text reinterpreted as
HTML without escaping meta-characters.

Impact: stored XSS. Any mandate value containing raw HTML/script
(e.g. `<img src=x onerror=alert(1)>`), whether entered directly in
the UI or written via the API by an integration/compromised agent,
executes in the browser of anyone who opens the Preview tab for that
mandate.

Fix: escape HTML special characters (&, <, >, ", ') before applying
the markdown-to-HTML regex substitutions, so any embedded tags render
as literal text instead of being interpreted as markup. Preserves all
existing markdown formatting (headers, bold, italic, lists, hr, line
breaks) since escaping runs before those regexes and none of them
rely on raw angle brackets from the input.

No backend change needed — this is purely a client-side rendering
fix; the raw mandate value stored server-side is unaffected.
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.

Stored XSS in Kaizen mandate preview (dangerouslySetInnerHTML without escaping)

1 participant