4.2 KiB · text History b868907

CSRF & XSS Prevention

CSRF Protection

Implemented Controls

Browser Pipeline (:browser pipeline in router)

  • protect_from_forgery plug applied to all browser routes
    • Generates CSRF token per session
    • Token validated on POST/PUT/DELETE/PATCH requests
    • Token stored in session and compared against request

Token Transmission

  • Form submissions: token included via hidden input field
  • AJAX/fetch requests: x-csrf-token header accepted
    • Phoenix automatically includes CSRF token in meta tag
    • JavaScript frameworks can read from document.querySelector('meta[name="csrf-token"]').content

Cookie Attributes

  • SameSite=Lax on session cookies
    • Prevents cross-site cookie sending on top-level navigation
    • Blocks CSRF on GET requests and same-site navigation
    • Allows GET requests to cross-site via browser navigation (e.g., clicking a link)

Exclusions (Intentional)

  • :api pipeline — Used by Gitea-compatible REST API and runner endpoints
    • No CSRF protection — acceptable because endpoints use token authentication (PAT, runner JWT)
    • Token-authenticated clients don’t automatically send cookies
  • :mobile_api pipeline — Mobile API endpoints
    • Uses personal access token authentication
    • No CSRF protection — acceptable for token-based auth

XSS Prevention

Implemented Controls

LiveView Auto-Escaping

  • Phoenix LiveView automatically escapes all interpolated values in HEEx templates
    • {@value} — HTML-escaped interpolation
    • <%= @value %> — HTML-escaped interpolation in tag bodies
    • {@value} in attribute values — attribute-escaped
  • Template compilation provides compile-time escaping guarantees

Markdown Sanitization

  • lib/git_gud/markdown.ex — HTML sanitization pipeline
    • Strips dangerous HTML elements (<script>, <iframe>, <object>, <embed>)
    • Strips event handler attributes (onload, onclick, etc.)
    • Strips javascript: URIs in href/src attributes
    • Allows safe subset: bold, italic, links, code blocks, tables, images
    • Processes user-generated content before rendering in templates

Content-Type Headers

  • All responses include appropriate Content-Type headers
  • JSON responses: application/json
  • HTML responses: text/html
  • Prevents MIME-type confusion attacks

Security Observations

Medium

No Content-Security-Policy (CSP) header

  • CSP provides defense-in-depth against XSS
  • Prevents inline script execution (except explicitly allowed)
  • Restricts sources for scripts, styles, images, fonts, etc.
  • Recommendation: add CSP header via Plug
    • Example: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';
    • Start with Content-Security-Policy-Report-Only for testing

No X-Frame-Options or X-Content-Type-Options headers

  • X-Frame-Options: DENY — prevents clickjacking
  • X-Content-Type-Options: nosniff — prevents MIME-type sniffing
  • Recommendation: add via put_secure_browser_headers (already in :browser pipeline)
    • Verify these headers are not being stripped by reverse proxy

LiveDashboard accessible

  • Phoenix LiveDashboard available at /dashboard/*
  • Exposes runtime metrics, process info, logger, IEx console
  • Risk: IEx console allows arbitrary code execution
  • Recommendation: disable dev_routes in production
    • config :git_gud, GitGudWeb.Endpoint, dev_routes: false
    • Or restrict to admin users only via plug

MailboxPreview accessible

  • Swoosh MailboxPreview at /dev/mailbox in development
  • Exposes received emails (including magic links with tokens)
  • Recommendation: disable in production via config :swoosh, local: false

Low

Markdown sanitization needs periodic review

  • XSS vectors evolve over time (e.g., SVG onload, iframe src, data URIs)
  • Recommendation: add security test suite with known XSS payloads
  • Test against latest OWASP XSS cheatsheet regularly
  • Consider using a well-maintained sanitization library (e.g., bleach-like Elixir port)

Inline JavaScript in templates

  • If phx-hook or colocated hooks used in templates, inline scripts may be injected
  • Recommendation: ensure all JavaScript is loaded via assets bundle (app.js)
  • Use phx-hook with external hooks defined in assets/js/ where possible