fix(frontend): sanitize AI chat markdown before rendering#2229
fix(frontend): sanitize AI chat markdown before rendering#2229
Conversation
There was a problem hiding this comment.
1 issue found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/lib/sanitize-markdown.ts">
<violation number="1" location="frontend/src/lib/sanitize-markdown.ts:6">
P1: Sanitizing raw markdown with DOMPurify is insufficient; markdown syntax can still produce unsafe links after rendering. Sanitize the rendered HTML (or enforce markdown URL allow-listing) at render time.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
@cursor review |
### Motivation - Prevent HTML/attribute injection in AI-generated chat markdown so user-supplied or LLM-produced HTML cannot render active elements (e.g., `<a>`, `<h1>`, inline `style`) in the chat UI. - Keep full markdown rendering experience while removing dangerous tags/attributes to avoid breaking most markdown and HTML rendering. - Strengthen the browser-side policy to reduce inline-attribute/script attack surface. ### Description - Add a markdown sanitization helper using `DOMPurify` at `frontend/src/lib/sanitize-markdown.ts` and forbid risky attributes (notably `style`) via `FORBID_ATTR`. - Sanitize AI output before rendering by applying `sanitizeMarkdownContent` to streaming assistant text and persisted assistant text in `Messages` (`frontend/src/components/chat/messages.tsx`). - Sanitize children passed into the reusable AI `Response` component (`frontend/src/components/ai-elements/response.tsx`) so other AI surfaces inherit the fix. - Add `dompurify` to frontend dependencies (`frontend/package.json` / `pnpm-lock.yaml`). - Harden frontend CSP headers by adding `base-uri 'self'` and `script-src-attr 'none'` in `frontend/next.config.mjs` to reduce inline/script attribute risk. ### Testing - Ran code style/lint checks: `pnpm --dir frontend exec biome check --write src/components/ai-elements/response.tsx src/components/chat/messages.tsx src/lib/sanitize-markdown.ts` (succeeded). - Ran workspace checks: `pnpm -C frontend check` (succeeded). - Ran TypeScript typecheck: `pnpm -C frontend run typecheck` (succeeded, `tsc` returned no errors). - Installed `dompurify` via `pnpm --dir frontend add dompurify@3.2.6` (succeeded) and updated lockfile. - Attempted local visual validation by running `pnpm -C frontend dev --port 3000` and capturing a Playwright screenshot; Next server started and a browser screenshot artifact was produced, but request rendering returned `500` due to missing required environment variables (`NEXT_PUBLIC_APP_URL`, `NEXT_PUBLIC_API_URL`) in this execution environment, so full end-to-end manual verification could not be completed here.
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/components/ai-elements/response.tsx">
<violation number="1" location="frontend/src/components/ai-elements/response.tsx:21">
P1: The new safe link/image prefix restrictions are overrideable because `{...props}` is spread after them, allowing callers to bypass the intended markdown URL policy.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
### Motivation - Prevent HTML/attribute injection in AI-generated chat markdown so user-supplied or LLM-produced HTML cannot render active elements (e.g., `<a>`, `<h1>`, inline `style`) in the chat UI. - Keep full markdown rendering experience while removing dangerous tags/attributes to avoid breaking most markdown and HTML rendering. - Strengthen the browser-side policy to reduce inline-attribute/script attack surface. ### Description - Add a markdown sanitization helper using `DOMPurify` at `frontend/src/lib/sanitize-markdown.ts` and forbid risky attributes (notably `style`) via `FORBID_ATTR`. - Sanitize AI output before rendering by applying `sanitizeMarkdownContent` to streaming assistant text and persisted assistant text in `Messages` (`frontend/src/components/chat/messages.tsx`). - Sanitize children passed into the reusable AI `Response` component (`frontend/src/components/ai-elements/response.tsx`) so other AI surfaces inherit the fix. - Add `dompurify` to frontend dependencies (`frontend/package.json` / `pnpm-lock.yaml`). - Harden frontend CSP headers by adding `base-uri 'self'` and `script-src-attr 'none'` in `frontend/next.config.mjs` to reduce inline/script attribute risk. ### Testing - Ran code style/lint checks: `pnpm --dir frontend exec biome check --write src/components/ai-elements/response.tsx src/components/chat/messages.tsx src/lib/sanitize-markdown.ts` (succeeded). - Ran workspace checks: `pnpm -C frontend check` (succeeded). - Ran TypeScript typecheck: `pnpm -C frontend run typecheck` (succeeded, `tsc` returned no errors). - Installed `dompurify` via `pnpm --dir frontend add dompurify@3.2.6` (succeeded) and updated lockfile. - Attempted local visual validation by running `pnpm -C frontend dev --port 3000` and capturing a Playwright screenshot; Next server started and a browser screenshot artifact was produced, but request rendering returned `500` due to missing required environment variables (`NEXT_PUBLIC_APP_URL`, `NEXT_PUBLIC_API_URL`) in this execution environment, so full end-to-end manual verification could not be completed here.
|
Could not push Autofix changes. The PR branch has conflicting changes. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/components/ai-elements/response.tsx">
<violation number="1" location="frontend/src/components/ai-elements/response.tsx:27">
P1: `rehypePlugins` can be overridden by `...props`, allowing sanitization to be bypassed. Apply `...props` first and enforce the sanitizing `rehypePlugins` afterward.</violation>
</file>
<file name="frontend/src/lib/sanitize-markdown.ts">
<violation number="1" location="frontend/src/lib/sanitize-markdown.ts:36">
P2: `rehype-sanitize` is applied after `rehype-katex`, which can strip KaTeX output and break math rendering. Sanitize untrusted markdown first, then run `rehype-katex`.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
I committed and pushed: fix(frontend): enforce sanitizing rehypePlugins and correct plugin order. |
Co-authored-by: Chris Lo <topher-lo@users.noreply.github.com>
Co-authored-by: Chris Lo <topher-lo@users.noreply.github.com>
Co-authored-by: Chris Lo <topher-lo@users.noreply.github.com>
…anges Co-authored-by: Chris Lo <topher-lo@users.noreply.github.com>


Problem: AI chat markdown could render unsafe HTML/attributes; DOMPurify caused SSR blank output and hydration mismatches. CSP alone doesn’t prevent dangerous protocols or clickable phishing links.
Solution: