Web Security

Content Security Policy for AI-Generated Interfaces

A practical CSP guide for AI-generated interfaces, streamed responses, remote assets, workers, frames, and safe browser defense in depth.

By PermsAI Editorial Team
Content Security Policy for AI-Generated Interfaces featured image

Content Security Policy for AI-generated interfaces is a browser defense-in-depth control. It can restrict where scripts, styles, frames, images, connections, and forms may go, but it cannot authenticate a user, authorize a tool call, sanitize model output, or make a prompt trustworthy. The useful question is which browser capabilities this interface needs and which can safely be denied.

Why AI interfaces pressure CSP

AI interfaces stream responses, render Markdown, show code previews, load retrieved images, open approval dialogs, and sometimes connect to WebSockets or workers. Teams often respond by adding broad origins or unsafe inline behavior until the page works. Each exception expands the browser execution surface. Treat every SDK, chat widget, analytics tag, remote asset, and embedded preview as a policy change with an owner.

CSP applies to the browser document. It does not govern server-to-server model calls, database authorization, or a sandbox network policy. Keep those boundaries explicit and pair CSP with Secure Rendering of LLM Output.

Inventory capabilities before writing directives

List application scripts, inline styles, API and streaming endpoints, image origins, fonts, frames, workers, form destinations, and telemetry. Record why each origin is needed and whether a same-origin alternative exists. A model-generated URL is data; allowing an image or connection origin does not authorize an agent to contact it.

The default-src directive is a fallback for fetch directives without a more specific declaration. It is a baseline, not a substitute for reviewing each resource type. Declare explicit directives for capabilities the product uses so a future browser feature does not silently inherit an overly broad default.

Script policy

script-src is usually the highest-impact directive. Prefer same-origin scripts, nonces or hashes for intentionally inline code, and builds that emit external assets. Avoid unsafe-inline where feasible because it weakens protection against injected script. Avoid unsafe-eval unless a reviewed runtime genuinely requires it; generated model text must never become code evaluation.

Third-party scripts deserve separate review: identify the owner, data collected, update path, and failure behavior. A vendor origin can serve any script permitted by that origin. If a framework uses nonces or a trusted dynamic-loading model, follow its current documentation and test the production response; do not copy a strict-dynamic example without understanding support and fallback behavior.

Styles, images, and connections

style-src controls style resources and inline style behavior. Do not treat relaxing it as harmless: injected style can obscure warnings, alter links, or support other attacks. Prefer compiled styles and narrowly documented nonces or hashes for required inline rules.

img-src should list only image origins the interface needs. Remote images can reveal a viewer’s IP address and referrer to a third party. data and blob schemes are capabilities, not free conveniences; enable them only for known previews or generated client artifacts.

connect-src governs browser requests such as API calls, fetch streams, WebSockets, model proxies, and telemetry. Allow exact application and streaming endpoints. A connection allowlist does not validate a destination selected by an agent on the server and does not replace API authorization.

Frames, forms, objects, and workers

Use frame-src for frames the page may load and frame-ancestors to control which sites may embed the page. They solve different problems. An AI document preview should be isolated and hosted only on a trusted origin; do not turn a remote preview into a general scripting environment.

object-src none is a strong modern baseline when legacy plugin content is unnecessary. base-uri self limits unexpected base URL changes. form-action self or a small allowlist prevents generated or injected forms from posting to arbitrary destinations. If the app uses workers, declare the required worker source using current browser documentation and test worker creation in production.

Generated HTML and streaming

CSP is not a sanitizer. Model-generated HTML, Markdown raw-HTML extensions, and links still need context-appropriate parsing, URL policy, and sanitization. A strict CSP can reduce impact from some injection paths, but it does not make an unsafe HTML sink safe. Keep the renderer policy in Secure Rendering of LLM Output.

Streaming changes timing, not trust. Apply the same output policy to each completed component or buffered fragment. Do not treat a streamed chunk as a script template, DOM instruction, or permission to call a tool. CSP may block some loads after the fact; it cannot validate partial JSON or stop a server-side side effect.

AI UI CSP policy map

UI capabilityRequired capabilityRelevant directiveSafe defaultReason to loosenRisk introduced
App JavaScriptSame-origin bundlesscript-srcself plus nonce/hashReviewed vendor runtimeMore executable code
Streaming APIFetch or WebSocketconnect-srcSame-origin endpointSeparate model proxyData exfiltration path
Remote imagesSelected image hostsimg-srcselfRequired public mediaTracking and disclosure
WorkerWorker script/blobworker-srcselfLocal previewMore execution surface
Iframe previewTrusted frameframe-srcnoneDocument viewerEmbedded trust boundary
FontsKnown font hostfont-srcselfApproved CDNThird-party request
AnalyticsTelemetry script/endpointscript/connect-srcDisabledMeasured product needData and supply-chain risk

Tie every exception to a ticket, owner, review date, and test. The matrix is a design record, not a reason to permit every row.

Report first, then enforce

Use Content-Security-Policy-Report-Only to observe violations while fixing legitimate dependencies. Report-only does not block anything. Reports are incomplete and can contain sensitive URLs, so send them to an authenticated, rate-limited collector with retention and redaction. Compare reports with the capability inventory instead of blindly adding every origin.

After the policy is minimal, enforce Content-Security-Policy. Test login, streaming, Markdown rendering, image previews, approval flows, error pages, and degraded states. Use browser DevTools, automated header assertions, and security tests. Re-test after framework upgrades, new SDKs, model UI changes, or a switch from polling to WebSockets.

Deployment sequence

  1. Inventory resources and trust boundaries.
  2. Write the narrowest policy that should work.
  3. Deploy report-only in a representative environment.
  4. Observe and classify violations.
  5. Remove accidental dependencies or justify exceptions.
  6. Enforce the policy.
  7. Monitor and review changes continuously.

Practical checklist

  • Keep default-src restrictive and declare used resource types explicitly.
  • Prefer nonces, hashes, and external bundles over unsafe-inline.
  • Avoid unsafe-eval; never evaluate model output.
  • Allowlist exact API, stream, image, font, frame, and telemetry origins.
  • Use object-src none, deliberate base-uri, and constrained form-action.
  • Distinguish frame-src from frame-ancestors.
  • Treat remote media and third-party scripts as privacy and supply-chain decisions.
  • Keep CSP separate from authorization, output sanitization, and server egress controls.
  • Test streamed UI, workers, previews, and failure paths in production builds.
  • Protect and minimize violation reports.
  • Review exceptions when dependencies or model-driven UI behavior changes.

Sources

  • W3C Content Security Policy specification
  • MDN Content Security Policy documentation
  • OWASP Content Security Policy Cheat Sheet
  • OWASP Cross-Site Scripting Prevention Cheat Sheet
  • Current framework security and CSP documentation

CSP works best as one layer: trusted code authorizes actions, safe components render data, and the browser policy limits what a mistake can load or execute.

What CSP cannot fix

A policy does not know whether a logged-in user owns a document, whether an agent may send a message, or whether a retrieved instruction is malicious. Those decisions belong to server-side identity and authorization controls. A page can have an excellent CSP and still leak tenant data through an API that returns the wrong object. It can also display dangerous content safely while a separate tool endpoint performs an unauthorized action. Link CSP review to the application threat model and to the authorization tests for each state-changing route.

CSP also does not remove dependency risk. A permitted first-party bundle can contain a vulnerable dependency, and a permitted third-party script can change later. Pin dependencies, review updates, and keep the allowed origin set small. When an AI SDK requires a remote origin, document exactly which browser request it makes and whether a server-side proxy can remove that exception.

Testing policy changes

Automated tests should assert the response header on authenticated and unauthenticated pages, error routes, streamed responses, and preview pages. Exercise the interface with JavaScript disabled where practical, verify that essential functions degrade safely, and check that a violation report is generated for an intentionally blocked test resource. Review browser console violations in a controlled test environment, not by weakening production policy until warnings disappear.

For generated links and media, test both allowed and disallowed origins. For frames, test embedding from an approved parent and rejection from an unapproved parent. For workers and WebSockets, test the exact production build and deployment headers because development tooling often has different resource requirements. Treat each policy change as a security-sensitive configuration change with code review and rollback.