Skip to main content

XSS (Cross-Site Scripting)

Most XSS in React is automatic — JSX escapes string interpolation by default. The dangerous patterns:

❌ dangerouslySetInnerHTML on user input

Renders raw HTML. If the input is user-controlled, sanitize first.

❌ Unsanitized markdown with raw HTML enabled

Most markdown libraries disable raw HTML by default. Don’t enable it for user input.

❌ Setting href from user input

javascript:... URLs execute on click. Validate and only allow http:// / https:// / mailto:.

✅ Plain JSX interpolation

<div>{userText}</div> — safe. Auto-escaped.

Sanitizing

For markdown, prefer react-markdown — safe by default.

CSRF (Cross-Site Request Forgery)

vly’s auth uses HTTP-only, SameSite=Lax cookies, which prevents standard CSRF. The cookie is sent only on same-site navigations and same-site fetches; cross-site POST requests don’t include the auth cookie. If you implement custom auth or accept requests from other origins (CORS), you’ll need:
  • CSRF tokens for state-changing requests.
  • Origin / Referer header validation.
  • SameSite=Strict for higher protection (with the UX tradeoff).

Content Security Policy (CSP)

vly serves a default CSP that:
  • Allows scripts only from the app’s own origin.
  • Allows images from the app + Convex storage CDN.
  • Denies inline event handlers.
To add allowed hosts (e.g., your analytics provider), configure in app/layout.tsx or the Convex HTTP route.

Tips

Treat all external input as hostile. That includes URL params, form values, file uploads, and webhook payloads.
Use a Content Security Policy in production. Prevents XSS even if a bug slips through.

Input validation

First line of defense.

Auth best practices

Auth-specific guidance.

Security overview

Broader model.
Last modified on April 18, 2026