Short answer
The security model reduces runtime network and script exposure, but it does not protect against a compromised browser, malicious extension, operating-system telemetry, or user-downloaded files after they leave the page.
Build boundary
Verification path
Use the verification page, browser DevTools, and repository privacy tests to inspect the behavior instead of relying on marketing language.
Exact Content Security Policy
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob:; font-src 'self'; connect-src 'none'; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; upgrade-insecure-requests
Why connect-src none matters
connect-src 'none' blocks fetch, XHR, WebSocket, EventSource, and sendBeacon destinations in supporting browsers after the page is loaded. It is a deployment control that supports the local-processing claim for the privacy build.
The CSP directive is declarative and depends on browser enforcement. tests/no-network-processing.js checks the same property empirically: it patches window.fetch, XMLHttpRequest.prototype.open, and navigator.sendBeacon to throw if invoked, then runs representative tool flows and fails if any of those patched functions were called or if any non-same-origin request was observed.
Meta tag vs HTTP header enforcement
The generator writes the CSP string into an HTML meta tag when a page does not already carry one, and separately writes the same string as an HTTP header in the generated _headers file. That duplication is deliberate, not redundant: per the Content Security Policy specification, directives such as frame-ancestors are ignored when a policy is delivered only through a meta element and take effect solely through the HTTP header.
On a host that serves the generated _headers file, frame-ancestors 'none' is enforced through the response header regardless of the meta tag. The meta tag mainly reinforces the directives that meta delivery does support, such as script-src and connect-src, as a second layer if a header were ever misconfigured.
FAQ
Does CSP make the app risk-free?
No. CSP reduces classes of network and script exposure, but it is not a complete security boundary.
Why allow unsafe-inline styles?
The current pages include inline style attributes, so style-src 'unsafe-inline' remains a future hardening task.
Does the privacy build use third-party runtime scripts?
The generated artifact is audited so it does not intentionally load third-party runtime scripts.
Does the privacy build set a Permissions-Policy?
Yes. Camera, microphone, geolocation, payment, USB, Bluetooth, accelerometer, gyroscope, magnetometer, and interest-cohort are all set to an empty allowlist.
Is the staging URL indexable?
No. The Worker adds a noindex header and a robots meta tag only when the request hostname ends in .workers.dev, and leaves privacy.convertunlimited.com unmodified.
Where does the CSP get applied twice?
Once as an HTML meta tag inserted by the generator when no CSP meta tag already exists, and once as a header in the generated _headers file, so the policy still applies even if a host ignores the meta tag.
Does the meta tag alone enforce frame-ancestors?
No. Per the CSP specification, frame-ancestors only takes effect when delivered as an HTTP header, which is why the generator also writes the policy into the _headers file rather than relying on the meta tag alone.
Review note
Trust documentation reviewed: May 2026. These pages describe the current public and privacy-build architecture and should be updated when deployment, telemetry, or runtime dependencies change.