chatcn

Security

chatcn renders user-generated content. Every text rendering path is protected against XSS, URL injection, file upload attacks, and content spoofing.

Security Defaults

SettingDefaultReason
Markdown raw HTMLBlockedXSS prevention
Allowed link protocolshttp, https, mailto onlyBlock javascript: and data: URIs
External linkstarget="_blank" rel="noopener noreferrer"Prevent tab-napping
SVG file uploadsBlockedSVG can contain scripts
Max message render length10,000 charsPrevent rendering DoS
Max reactions per message8Prevent reaction spam
File size limit (UI)25MBPrevent large uploads
Bidi override strippingOnPrevent text spoofing
Emoji validationOnPrevent 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 }) // 10MB

sanitizeFileName(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>")      // false

stripBidiOverrides(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-markdown with element allowlist (no rehypeRaw)
  • 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

FeatureDefaultNotes
Read receiptsOff (opt-in)Users should control their own
Presence indicatorsOff (opt-in)Users should control visibility
Typing indicatorOnStandard UX expectation
Avatar URLsProxy recommendedCan 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