Security
chatcn renders user-generated content. Every text rendering path is protected against XSS, URL injection, file upload attacks, and content spoofing.
Security Defaults
| Setting | Default | Reason |
|---|---|---|
| Markdown raw HTML | Blocked | XSS prevention |
| Allowed link protocols | http, https, mailto only | Block javascript: and data: URIs |
| External links | target="_blank" rel="noopener noreferrer" | Prevent tab-napping |
| SVG file uploads | Blocked | SVG can contain scripts |
| Max message render length | 10,000 chars | Prevent rendering DoS |
| Max reactions per message | 8 | Prevent reaction spam |
| File size limit (UI) | 25MB | Prevent large uploads |
| Bidi override stripping | On | Prevent text spoofing |
| Emoji validation | On | Prevent non-emoji injection |
Built-in Security Utilities
Import from @/components/ui/chat:
sanitizeUrl(url)
Blocks javascript:, data:, vbscript:, blob: protocols. Only allows http://, https://, mailto:.
import { sanitizeUrl } from "@/components/ui/chat"
sanitizeUrl("https://example.com") // "https://example.com"
sanitizeUrl("javascript:alert(1)") // "#"
sanitizeUrl("data:text/html,<script>") // "#"validateFile(file, opts?)
Blocks dangerous extensions (.exe, .bat, .svg, .html, .js + 25 more). Enforces 25MB size limit.
import { validateFile } from "@/components/ui/chat"
const result = validateFile(file)
if (!result.valid) {
console.error(result.error) // "File type .exe is not allowed"
}
// Custom size limit
validateFile(file, { maxSize: 10 * 1024 * 1024 }) // 10MBsanitizeFileName(name)
Strips path traversal (/ \), null bytes, bidi overrides. Truncates to 100 chars.
import { sanitizeFileName } from "@/components/ui/chat"
sanitizeFileName("../../etc/passwd") // ".._.._ etc_passwd"
sanitizeFileName("report.pdf") // "report.pdf"isValidEmoji(str)
Unicode regex validation for reactions. Prevents non-emoji injection.
import { isValidEmoji } from "@/components/ui/chat"
isValidEmoji("👍") // true
isValidEmoji("<script>") // falsestripBidiOverrides(text)
Removes U+202A-202E, U+2066-2069 (RLO attack prevention).
import { stripBidiOverrides } from "@/components/ui/chat"
stripBidiOverrides("hello\u202Eworld") // "helloworld"truncateMessage(text, maxLength?)
Caps at 10,000 chars by default to prevent rendering DoS. Returns { text, truncated }.
import { truncateMessage } from "@/components/ui/chat"
truncateMessage("short") // { text: "short", truncated: false }
truncateMessage(longText, 5000) // { text: "...(truncated)", truncated: true }sanitizeSenderName(name)
Strips bidi overrides and truncates to 100 chars.
import { sanitizeSenderName } from "@/components/ui/chat"
sanitizeSenderName("Alice") // "Alice"formatReactionCount(count)
Floors at 0, caps at "999+".
import { formatReactionCount } from "@/components/ui/chat"
formatReactionCount(5) // "5"
formatReactionCount(1500) // "999+"
formatReactionCount(-1) // "0"displayHostname(url)
Safe URL display showing only hostname. Prevents misleading long URLs.
import { displayHostname } from "@/components/ui/chat"
displayHostname("https://example.com/very/long/path") // "example.com"XSS Prevention
All text rendering uses React JSX (auto-escaped). No dangerouslySetInnerHTML anywhere except Shiki code output.
- Plain text messages render through React text nodes
- Markdown rendering uses
react-markdownwith element allowlist (norehypeRaw) - Link rendering overrides
<a>tags to sanitize URLs - Code block language names stripped to alphanumeric only
- Mention names treated as untrusted text
File Upload Security
Frontend validation via validateFile():
- Blocked extensions:
.exe,.bat,.svg,.html,.js,.sh+ 25 more - SVG specifically blocked (can contain
<script>tags) - 25MB size limit (configurable)
- File name sanitization strips path traversal and null bytes
Privacy Defaults
| Feature | Default | Notes |
|---|---|---|
| Read receipts | Off (opt-in) | Users should control their own |
| Presence indicators | Off (opt-in) | Users should control visibility |
| Typing indicator | On | Standard UX expectation |
| Avatar URLs | Proxy recommended | Can be tracking pixels |
Backend Responsibilities
chatcn is a UI library. These are NOT handled by chatcn:
- Authentication & authorization
- Message encryption (E2E, at-rest)
- Rate limiting
- Content moderation
- SSRF prevention (link preview fetching)
- File malware scanning
- EXIF stripping from images
- Input length validation (server-side)
- Audit logging