Short summary
modules/home/code-line.tsx uses dangerouslySetInnerHTML to inject syntax-highlighting <span> tags, but never escapes HTML special characters (<, >, &) in the input first. Any code line containing angle brackets (TypeScript generics, JSX, comparison operators) will render as broken or corrupted HTML. The component itself has an internal TODO comment acknowledging it should be replaced with a proper library.
Steps to reproduce
- Open
modules/home/hero-code.tsx
- Add a line containing angle brackets to
codeSnippet, for example:
const codeSnippet = `...
const elements: Array<string> = [];
const isSmaller = a < b;
return <div>Hello</div>;
`;
- Run the dev server and visit the homepage (
/)
- Observe the "code demo" card
Expected behavior
The code lines should render as readable, syntax-highlighted text. Angle brackets and HTML-special characters should be displayed as literal characters.
Actual behavior
Array<string> → the <string> part is parsed as an HTML element and disappears from the DOM
a < b → < b opens a malformed HTML tag, corrupting everything that follows
<div>Hello</div> → renders as a real DOM <div> inside the code block
The highlightCode function in code-line.tsx (lines 24–30) does string replacements that produce raw HTML, then passes the result directly to dangerouslySetInnerHTML without escaping entities first:
// modules/home/code-line.tsx:24-30
const highlightCode = (code: string) => {
return code
.replace(/import|from|export|.../g, '<span class="text-red-500...">$&</span>')
.replace(/'[^']*'/g, '<span class="text-amber-600...">$&</span>')
// ... no HTML entity escaping anywhere
}
// line 21
return <span dangerouslySetInnerHTML={{ __html: highlightCode(highlighted) }} />;
The component even has a self-aware comment at lines 6-8:
// Note: This is a very simplistic implementation and should be replaced with a proper library like prismjs or shiki in production
Affected area
Other
Environment
All browsers, all OSes. Reproducible locally by editing hero-code.tsx to include any JSX or generic TypeScript in codeSnippet. The current hardcoded snippet happens to avoid angle brackets, which is why this hasn't surfaced yet — but it's a latent bug waiting to break the homepage.
Root cause:
// Should escape entities BEFORE injecting spans:
const escapeHtml = (str: string) =>
str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
const highlightCode = (code: string) => {
const safe = escapeHtml(code); // escape first
return safe.replace(/import|from|.../g, '<span ...>$&</span>');
};
Better long-term fix (as the existing TODO suggests): replace the entire CodeLine component with shiki or prism-react-renderer, both of which handle escaping correctly and provide real language-aware tokenization.
Screenshots, logs, or recordings
Affected file: modules/home/code-line.tsx lines 24–39
Consumer: modules/home/hero-code.tsx lines 72–79
Confirmation
Short summary
modules/home/code-line.tsxusesdangerouslySetInnerHTMLto inject syntax-highlighting<span>tags, but never escapes HTML special characters (<,>,&) in the input first. Any code line containing angle brackets (TypeScript generics, JSX, comparison operators) will render as broken or corrupted HTML. The component itself has an internal TODO comment acknowledging it should be replaced with a proper library.Steps to reproduce
modules/home/hero-code.tsxcodeSnippet, for example:/)Expected behavior
The code lines should render as readable, syntax-highlighted text. Angle brackets and HTML-special characters should be displayed as literal characters.
Actual behavior
Array<string>→ the<string>part is parsed as an HTML element and disappears from the DOMa < b→< bopens a malformed HTML tag, corrupting everything that follows<div>Hello</div>→ renders as a real DOM<div>inside the code blockThe
highlightCodefunction incode-line.tsx(lines 24–30) does string replacements that produce raw HTML, then passes the result directly todangerouslySetInnerHTMLwithout escaping entities first:The component even has a self-aware comment at lines 6-8:
Affected area
Other
Environment
All browsers, all OSes. Reproducible locally by editing
hero-code.tsxto include any JSX or generic TypeScript incodeSnippet. The current hardcoded snippet happens to avoid angle brackets, which is why this hasn't surfaced yet — but it's a latent bug waiting to break the homepage.Root cause:
Better long-term fix (as the existing TODO suggests): replace the entire
CodeLinecomponent withshikiorprism-react-renderer, both of which handle escaping correctly and provide real language-aware tokenization.Screenshots, logs, or recordings
Affected file:
modules/home/code-line.tsxlines 24–39Consumer:
modules/home/hero-code.tsxlines 72–79Confirmation