CSP for Sentry: the SDK and CSP reports

connect-src https://*.sentry.io; worker-src 'self' blob:

Sentry’s browser SDK needs connect-src for the ingest host in your DSN, which Sentry’s loader docs write as *.sentry.io, and Session Replay adds worker-src 'self' blob: for its compression worker. Loading the SDK from Sentry’s CDN or Loader Script adds script-src https://browser.sentry-cdn.com https://js.sentry-cdn.com. To collect your policy’s violations in Sentry as well, point report-uri and report-to at the project’s Security Header endpoint, under Project Settings > Security Headers.

The policy, in Report-Only

Reporting-Endpoints: csp-endpoint="https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef"
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://browser.sentry-cdn.com https://js.sentry-cdn.com; connect-src 'self' https://*.sentry.io; worker-src 'self' blob:; child-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; report-uri https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef; report-to csp-endpoint

The IDs and key are placeholders: copy yours from the project. Report-Only blocks nothing; the browser reports each violation, and Sentry collects them. The builder shows no meta tag, because a meta tag can’t carry a report-only policy, and finds one low point: report-uri is deprecated in favor of report-to, and Sentry recommends both. Chrome, Firefox 149 and later and Safari 16.4 and later read report-to, by MDN’s compatibility data, and under CSP Level 3 they ignore report-uri when both are present; older browsers still need it. Sentry’s example also sends the older Report-To header, with the same URL.

Where the SDK sends events

  • The DSN’s host. Events go to the ingest host in your DSN, o<org-id>.ingest.sentry.io, at /api/<project-id>/envelope/. The builder reads Sentry’s bare *.sentry.io as any subdomain over https, or over http too on an http page; https://*.sentry.io pins it to HTTPS. You can narrow it to the exact host in your DSN.
  • A tunnel. With tunnel: "/tunnel" in Sentry.init, the SDK posts to your own origin, and your server forwards to Sentry. connect-src 'self' covers it, and ad blockers don’t treat it as a third-party request.
  • Sentry’s guide also asks for its host in connect-src or default-src when you collect reports, so the policy above covers both jobs.

Session Replay

Replay compresses in a Web Worker made from a blob: URL, so worker-src 'self' blob:; Safari 15.4 and older also need child-src 'self' blob:. worker-src falls back to child-src, then script-src, then default-src, so if you set none of them, default-src decides and needs the blob: instead. If blob: workers are out, Sentry lets you host its compression worker yourself, under 'self'.

Rolling out

Report-Only first, then enforce. You can send both headers at once: enforce the policy you trust and report the stricter next one. Add sentry_environment or sentry_release to the report URL’s query string to tag reports.

In nginx

add_header Reporting-Endpoints 'csp-endpoint="https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef"' always;
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://browser.sentry-cdn.com https://js.sentry-cdn.com; connect-src 'self' https://*.sentry.io; worker-src 'self' blob:; child-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; report-uri https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef; report-to csp-endpoint" always;

Try it in the CSP Builder

everything that is fetched and has no directive of its own
scripts, inline and loaded
fetch(), XMLHttpRequest, WebSocket and EventSource
Worker, SharedWorker and ServiceWorker scripts
frames and workers with no directive of their own
<object>, <embed> and <applet>
the URLs a <base> element may point at
who may frame this page
where violation reports are posted
the Reporting API endpoint violation reports go to

A nonce has to be fresh for every response, so 'nonce-REPLACE_ME' is a placeholder: your server fills it in and puts the same value in the <script nonce=…> tag.

1 finding worst low

10 directives · report-only

Content-Security-Policy-Report-Only

default-src 'self'; script-src 'self' https://browser.sentry-cdn.com https://js.sentry-cdn.com; connect-src 'self' https://*.sentry.io; worker-src 'self' blob:; child-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; report-uri https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef; report-to csp-endpoint

The same policy as a meta tag

A meta tag can only enforce a policy, never report one, so this one has to go out as a header.

Findings · worst low

  • low · report-uri report-uri is deprecated and report-to replaces it. Older browsers only read this one, so keep it alongside if it still earns its place.

Every directive, in plain words

DirectiveWhat it governsSources
default-srceverything that is fetched and has no directive of its own
  • 'self' this origin only
script-src
→ default-src
scripts, inline and loaded
  • 'self' this origin only
  • https://browser.sentry-cdn.com the host browser.sentry-cdn.com over https
  • https://js.sentry-cdn.com the host js.sentry-cdn.com over https
connect-src
→ default-src
fetch(), XMLHttpRequest, WebSocket and EventSource
  • 'self' this origin only
  • https://*.sentry.io any subdomain of sentry.io over https
worker-src
→ child-src → script-src → default-src
Worker, SharedWorker and ServiceWorker scripts
  • 'self' this origin only
  • blob: blob: URLs, made in the page
child-src
→ default-src
frames and workers with no directive of their own
  • 'self' this origin only
  • blob: blob: URLs, made in the page
object-src
→ default-src
<object>, <embed> and <applet>
  • 'none' nothing of this kind may load
base-urithe URLs a <base> element may point at
  • 'self' this origin only
frame-ancestorswho may frame this page
  • 'self' this origin only
report-uriwhere violation reports are posted
  • https://o123456.ingest.sentry.io/api/7890123/security/?sentry_key=0123456789abcdef violation reports are posted here
report-tothe Reporting API endpoint violation reports go to
  • csp-endpoint violation reports go to the endpoint of this name, set in a Reporting-Endpoints header

Checked against CSP Level 3: every directive, every source keyword, and the fallback chain that carries a directive to default-src. Nothing is uploaded, and no request is made to the site whose policy you paste.

Runs in your browser. Nothing you enter is sent anywhere.