Skip to content

docs(site): add Security concept page#1559

Open
decepulis wants to merge 6 commits into
mainfrom
claude/security-guide-eLBgE
Open

docs(site): add Security concept page#1559
decepulis wants to merge 6 commits into
mainfrom
claude/security-guide-eLBgE

Conversation

@decepulis
Copy link
Copy Markdown
Collaborator

@decepulis decepulis commented May 18, 2026

Summary

Adds a new concepts/security page and moves CSP guidance off the installation page.

What's on the new page

  • Content Security Policy — directive table (media-src, img-src, connect-src, worker-src, style-src) with a starting-point example. <track> caption files land in media-src; HLS-driven captions stay under connect-src with the "when using HLS playback" qualifier preserved from the original installation copy.
  • crossorigin attribute — when to use anonymous vs use-credentials, with HTML and React code examples.
  • Subresource Integrity — HTML-only (gated with <FrameworkCase frameworks={["html"]}>) since CDN install isn't a documented React path. Example script tag and the version-pinning caveat.

Installation page
Deletes the ## CSP section. Adds a Security <DocsLinkCard> next to the existing Skins card in See also.

Sidebar
Slotted after concepts/accessibility in the Concepts section.

Editorial calls

  • Page type — concept page, sibling to accessibility / browser-support.
  • No "see also" section on the security page itself — inline MDN/W3C links throughout, matching accessibility's pattern.
  • No DRM/EME section — codebase audit confirmed v10 doesn't ship EME.
  • No safe-defaults paragraph — an earlier draft included one, but Codex review (and the codebase audit) surfaced a real XSS in the initial-construction attribute path that makes the claim unsafe to publish. Tracked separately in Bug: XSS via Unescaped Attribute Values in CustomMediaElement Shadow Root #1562. The "currently required" hedge on style-src is preserved from the original installation copy as a placeholder for future improvement.
  • No nonce/hash advice for style-src — the shadow-DOM <style> tags don't accept a user-plumbed nonce.

Closes

#966

Related

#1562 (XSS in serializeAttributes — separate fix, blocks restoring any safe-defaults claim here)

Test plan

  • Visit /docs/framework/html/concepts/security/ and verify all three sections render (CSP table, crossorigin, Subresource Integrity).
  • Visit /docs/framework/react/concepts/security/ and confirm Subresource Integrity is hidden, and the crossorigin example shows the React JSX form.
  • Visit /docs/framework/html/how-to/installation/ and confirm the ## CSP section is gone and a Security card appears in See also.
  • Confirm "Security" appears in the Concepts sidebar under both frameworks.
  • Search "CSP" via Cmd+K and confirm it lands on the new page.

https://claude.ai/code/session_016W6tiNqpHoZm6GrGHUVbVm


Note

Low Risk
Low risk documentation-only changes; primary impact is reorganizing guidance, so the main risk is broken links or framework-gated content not rendering as intended.

Overview
Adds a new Security concepts doc (concepts/security) covering CSP directives (with an example policy), proper use of the crossorigin attribute (HTML + React snippets), and HTML-only Subresource Integrity guidance for CDN installs.

Removes the CSP section from the installation guide and replaces it with a “See also” link card to the new Security page, and updates the docs sidebar to include concepts/security under Concepts.

Reviewed by Cursor Bugbot for commit da28c2d. Bugbot is set up for automated code reviews on this repo. Configure here.

Move CSP guidance off the installation page into a new
Concepts > Security page covering Content Security Policy,
crossorigin, and Subresource Integrity. Installation links
to it via See also.

Closes #966
@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment May 21, 2026 5:50pm

Request Review

@netlify
Copy link
Copy Markdown

netlify Bot commented May 18, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit da28c2d
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a0f45e9f7b1b4000821074b
😎 Deploy Preview https://deploy-preview-1559--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Size
/video (default) 38.57 kB
/video (default + hls) 172.02 kB
/video (minimal) 38.10 kB
/video (minimal + hls) 171.55 kB
/audio (default) 33.08 kB
/audio (minimal) 30.01 kB
/background 4.23 kB
Media (8)
Entry Size
/media/background-video 1.04 kB
/media/container 1.72 kB
/media/dash-video 236.58 kB
/media/hls-video 134.87 kB
/media/mux-audio 161.08 kB
/media/mux-video 161.00 kB
/media/native-hls-video 4.62 kB
/media/simple-hls-video 16.70 kB
Players (5)
Entry Size
/video/player 7.06 kB
/audio/player 5.18 kB
/background/player 3.92 kB
/live-video/player 7.07 kB
/live-audio/player 5.19 kB
Skins (30)
Entry Type Size
/video/minimal-skin.css css 4.67 kB
/video/skin.css css 4.73 kB
/video/minimal-skin js 38.02 kB
/video/minimal-skin.tailwind js 38.44 kB
/video/skin js 38.58 kB
/video/skin.tailwind js 38.99 kB
/audio/minimal-skin.css css 2.90 kB
/audio/skin.css css 2.93 kB
/audio/minimal-skin js 29.94 kB
/audio/minimal-skin.tailwind js 30.17 kB
/audio/skin js 33.09 kB
/audio/skin.tailwind js 33.28 kB
/background/skin.css css 133 B
/background/skin js 1.16 kB
/live-video/minimal-skin.css css 4.67 kB
/live-video/skin.css css 4.73 kB
/live-video/minimal-skin js 33.19 kB
/live-video/minimal-skin.tailwind js 33.24 kB
/live-video/skin js 33.34 kB
/live-video/skin.tailwind js 33.28 kB
/live-audio/minimal-skin.css css 2.90 kB
/live-audio/skin.css css 2.93 kB
/live-audio/minimal-skin js 25.19 kB
/live-audio/minimal-skin.tailwind js 24.99 kB
/live-audio/skin js 27.86 kB
/live-audio/skin.tailwind js 27.63 kB
/global.css css 176 B
/shared.css css 88 B
/tailwind.css css 228 B
/skin-element js 1.37 kB
UI Components (35)
Entry Size
/ui/alert-dialog 713 B
/ui/alert-dialog-close 363 B
/ui/alert-dialog-description 307 B
/ui/alert-dialog-title 309 B
/ui/buffering-indicator 2.11 kB
/ui/captions-button 2.08 kB
/ui/cast-button 2.08 kB
/ui/compounds 5.53 kB
/ui/controls 1.99 kB
/ui/error-dialog 2.51 kB
/ui/fullscreen-button 2.14 kB
/ui/hotkey 2.77 kB
/ui/menu 2.78 kB
/ui/mute-button 2.10 kB
/ui/pip-button 2.07 kB
/ui/play-button 2.08 kB
/ui/playback-rate-button 2.19 kB
/ui/playback-rate-menu 3.90 kB
/ui/popover 1.87 kB
/ui/poster 1.87 kB
/ui/seek-button 2.07 kB
/ui/seek-indicator 2.71 kB
/ui/seek-indicator-value 306 B
/ui/slider 1.19 kB
/ui/status-announcer 2.47 kB
/ui/status-indicator 2.50 kB
/ui/status-indicator-value 159 B
/ui/thumbnail 2.54 kB
/ui/time 1.92 kB
/ui/time-slider 3.04 kB
/ui/tooltip 1.79 kB
/ui/volume-indicator 2.74 kB
/ui/volume-indicator-fill 335 B
/ui/volume-indicator-value 328 B
/ui/volume-slider 3.56 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Size
/video (default) 32.29 kB
/video (default + hls) 164.70 kB
/video (minimal) 32.33 kB
/video (minimal + hls) 164.64 kB
/audio (default) 26.57 kB
/audio (minimal) 26.60 kB
/background 754 B
Media (7)
Entry Size
/media/background-video 575 B
/media/dash-video 235.21 kB
/media/hls-video 133.39 kB
/media/mux-audio 159.84 kB
/media/mux-video 159.74 kB
/media/native-hls-video 3.13 kB
/media/simple-hls-video 15.27 kB
Skins (27)
Entry Type Size
/tailwind.css css 228 B
/video/minimal-skin.css css 4.58 kB
/video/skin.css css 4.64 kB
/video/minimal-skin js 32.27 kB
/video/minimal-skin.tailwind js 37.00 kB
/video/skin js 32.19 kB
/video/skin.tailwind js 37.04 kB
/audio/minimal-skin.css css 2.77 kB
/audio/skin.css css 2.80 kB
/audio/minimal-skin js 26.54 kB
/audio/minimal-skin.tailwind js 26.25 kB
/audio/skin js 26.46 kB
/audio/skin.tailwind js 29.52 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 4.58 kB
/live-video/skin.css css 4.64 kB
/live-video/minimal-skin js 23.69 kB
/live-video/minimal-skin.tailwind js 28.15 kB
/live-video/skin js 23.74 kB
/live-video/skin.tailwind js 28.15 kB
/live-audio/minimal-skin.css css 2.77 kB
/live-audio/skin.css css 2.80 kB
/live-audio/minimal-skin js 19.95 kB
/live-audio/minimal-skin.tailwind js 22.38 kB
/live-audio/skin js 20.00 kB
/live-audio/skin.tailwind js 22.52 kB
UI Components (29)
Entry Size
/ui/alert-dialog 1.08 kB
/ui/buffering-indicator 1.86 kB
/ui/captions-button 2.08 kB
/ui/cast-button 2.04 kB
/ui/controls 1.84 kB
/ui/error-dialog 2.27 kB
/ui/fullscreen-button 2.08 kB
/ui/gesture 1.32 kB
/ui/hotkey 1.90 kB
/ui/live-button 2.10 kB
/ui/menu 4.29 kB
/ui/mute-button 2.03 kB
/ui/pip-button 2.04 kB
/ui/play-button 2.06 kB
/ui/playback-rate-button 2.04 kB
/ui/playback-rate-menu 4.61 kB
/ui/popover 2.32 kB
/ui/poster 1.69 kB
/ui/seek-button 2.07 kB
/ui/seek-indicator 1.87 kB
/ui/slider 3.22 kB
/ui/status-announcer 1.76 kB
/ui/status-indicator 1.96 kB
/ui/thumbnail 1.95 kB
/ui/time 2.51 kB
/ui/time-slider 2.97 kB
/ui/tooltip 2.72 kB
/ui/volume-indicator 1.98 kB
/ui/volume-slider 2.30 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (9)
Entry Size
. 7.47 kB
/dom 15.30 kB
/dom/media/custom-media-element 1.90 kB
/dom/media/dash 234.36 kB
/dom/media/google-cast 4.07 kB
/dom/media/hls 132.98 kB
/dom/media/mux 159.13 kB
/dom/media/native-hls 2.52 kB
/dom/media/simple-hls 14.62 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 996 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.39 kB
/html 696 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 1.96 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/string 192 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (3)
Entry Size
. 4.45 kB
/dom 6.32 kB
/hls 14.03 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

Adds plain-English definitions of Content Security Policy and
Subresource Integrity, gates each section with a "does this apply
to me?" line, and shows concrete HTML and React code for setting
crossorigin on the media element.
@decepulis decepulis marked this pull request as ready for review May 18, 2026 20:46
Copy link
Copy Markdown
Collaborator Author

@decepulis decepulis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex review (comment-only): useful structure, but I would not treat this as fully reliable yet. The page hits the right buckets for #966, but I see one material overclaim and a few docs-accuracy issues worth tightening.

  1. [P1] The safe-default paragraph overclaims URL handling. The new page says users do not need to scrub URLs before passing them to the player, and the PR body says source URLs are forwarded through setAttribute. That is true for later attribute changes, but not for initial custom-media construction: initial attributes are copied into an HTML string and assigned through shadowRoot.innerHTML, and serializeAttributes does not escape quote characters. A value like src='x" onerror="...' becomes a separate onerror attribute in the generated inner <video>. Either the docs should avoid promising this, or the implementation should escape/DOM-create the initial media element. Relevant code: packages/core/src/dom/media/custom-media-element/index.ts around the template/constructor path and packages/utils/src/dom/attributes.ts around serializeAttributes.

  2. [P2] The CSP table blurs how captions are loaded. Browser <track> loads are covered by media-src (MDN lists <track> under media-src), while HLS manifests/segments and any JS/fetch/XHR paths need connect-src. I would split this so readers do not incorrectly put ordinary caption files only under connect-src.

  3. [P2] The nonce/hash guidance for style-src sounds more actionable than the current implementation supports. The player injects internal <style> tags / shadow style fallbacks without an obvious user nonce plumbing path. Direct element.style.foo = ... is not blocked by style-src per MDN, but <style> tags and style attributes are. I would phrase this as "unsafe-inline is currently the practical requirement for Video.js injected style tags" rather than implying a user can wire nonce/hash support today.

  4. [P3] The SRI/package-manager sentence is directionally right but too broad. Safer wording: SRI is for browser-loaded CDN scripts; package-manager installs rely on lockfile/registry integrity instead.

Overall: useful guide shape, not hallucinated as a whole, but the safe-defaults sentence is the risky part I would not ship as written.

@decepulis decepulis requested a review from sampotts May 18, 2026 20:57
- Remove the safe-defaults paragraph; the player's initial-construction
  attribute interpolation isn't quote-safe (filed as separate issue).
- Add caption files loaded via <track> to media-src.
- Restore the original installation page's "when using HLS playback"
  scoping on connect-src captions, and "currently required" hedge on
  the style-src row.
- Drop the impractical nonce/hash suggestion — the player's shadow-DOM
  <style> tags don't accept a user-plumbed nonce.
- Restore the original installation CSP example shape (script-src,
  no default-src fallback).
Comment thread site/src/content/docs/concepts/security.mdx Outdated
@decepulis decepulis requested a review from sampotts May 21, 2026 17:42
The previous @10.0.0 example URL doesn't resolve yet (current package
is on 10.0.0-beta.23). A <version> placeholder reads as 'fill this in'
and won't go stale across releases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

## `crossorigin` attribute

When the player loads a video, caption file, or poster from another domain, the browser needs to know whether to send cookies and whether your page is allowed to read the response. The [`crossorigin`](https://developer.mozilla.org/docs/Web/HTML/Reference/Attributes/crossorigin) attribute tells the browser how to handle these requests.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"When the player" more accurately would be "When the html video element"

Because the crossorigin attribute doesn't affect the loading of Hls.js via xhr or fetch, that's handled by that request itself unless Hls.js uses that value in its requests but I'm not aware of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants