Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 23, 2025

Implements CSP enforcement for the double-iframe architecture to lock down AI-generated content. CSP is automatically configured based on the LLM provider and can be overridden via attribute. Includes security layering to isolate renderer from LLM API access.

Changes

Core Implementation

  • csp attribute: Optional override for custom policies
  • Provider-aware defaults: Auto-adds generativelanguage.googleapis.com for Gemini, blocks external connections for Chrome AI
  • Iframe csp attribute priority: Uses modern iframe csp attribute (Chrome/Edge support) as primary enforcement method
  • Fallback to meta tags: Gracefully falls back to CSP meta tag injection for browsers without iframe csp attribute support
  • CSP separation: Coordinator and renderer iframes get different CSP policies for security layering

Default Policies

Coordinator iframe (Layer 2) - Can access LLM API:

default-src 'none'
script-src 'unsafe-inline' 'unsafe-eval' blob:
style-src 'unsafe-inline'
img-src data: blob:
font-src data: blob:
frame-src blob:
connect-src https://generativelanguage.googleapis.com  // Gemini provider

Renderer iframe (Layer 3) - Isolated from external APIs:

default-src 'none'
script-src 'unsafe-inline' 'unsafe-eval' blob:
style-src 'unsafe-inline'
img-src data: blob:
font-src data: blob:
frame-src blob:
connect-src 'none'  // No external connections

unsafe-inline/unsafe-eval required for unpredictable AI-generated code. Sandbox isolation (allow-scripts without allow-same-origin) prevents parent/storage access.

Security Measures

  • Priority enforcement: iframe csp attribute set before src per HTML spec
  • Feature detection: Robust detection by setting attribute and verifying persistence
  • Layered isolation: Only coordinator can access LLM API, renderer is blocked from external connections
  • HTML entity escaping for CSP content via native DOM API
  • Regex-based tag matching (case-insensitive, handles malformed HTML)
  • CSP values cached (both coordinator and renderer) to avoid redundant computation

Security Layering

The coordinator iframe (Layer 2) needs to communicate with the LLM API, while the renderer iframe (Layer 3) displays AI-generated content. By applying different CSP policies:

  • Coordinator can make API calls to the LLM provider
  • Renderer is isolated and cannot make external connections
  • Custom CSP attribute applies to both layers (user has full control)

This prevents AI-generated code from making unauthorized API calls or exfiltrating data.

Usage

<!-- Auto-generated CSP based on provider -->
<generate-html provider="gemini" api-key="..." prompt="...">
</generate-html>

<!-- Custom CSP override (applies to both layers) -->
<generate-html 
  provider="gemini"
  csp="default-src 'self'; script-src 'unsafe-inline'; connect-src https://api.example.com">
</generate-html>

Files Modified

  • src/generate-html.js: CSP builder with separate policies for coordinator vs renderer, caching
  • src/coordinator.js: iframe csp attribute with fallback for renderer
  • README.md: Documentation

Demo Screenshot

Original prompt

This section details on the original issue you should resolve

<issue_title>Add CSP</issue_title>
<issue_description>We really need to think about CSP for this.

  1. By default everything should be locked down.
  2. Depending on the LLM API being used we should automatically add the correct origin to the iframe
  3. CSP should be able to be added to the custom element and these constraints are added to the iframes.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits November 23, 2025 23:44
- Add 'csp' to observedAttributes
- Implement _buildCSP method that creates default CSP policies
- Auto-detect provider and add appropriate origins (Gemini API)
- Inject CSP meta tags into both coordinator and renderer iframes
- Pass CSP configuration through the generation pipeline
- Default CSP: Lock down all external resources, only allow inline scripts/styles and blob URLs

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
- Add csp attribute to attributes table
- Document default CSP policy
- Explain provider-specific CSP configuration
- Add example of custom CSP usage

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
- Add proper HTML escaping for CSP content to prevent injection
- Use robust regex pattern matching for HTML tag detection
- Handle case-insensitive tags and various HTML structures
- Add _escapeHtml helper method using native DOM API
- Document why unsafe-inline/unsafe-eval are necessary for AI-generated content

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
- Cache built CSP in _currentCsp to reuse across generation calls
- Avoid rebuilding CSP on every triggerGeneration call

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Content Security Policy configuration Add Content Security Policy support with provider-aware defaults Nov 23, 2025
Copilot AI requested a review from PaulKinlan November 23, 2025 23:53
@PaulKinlan
Copy link
Owner

@copilot Chrome supports csp on the iframe element (https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/csp) I would like to make sure that we use that as a priority, and if not available the add to the html.

Copilot AI and others added 2 commits December 5, 2025 15:35
- Prioritize iframe csp attribute (Chrome/Edge support)
- Set csp attribute before src assignment per spec
- Fall back to CSP meta tag injection for unsupported browsers
- Update README to document implementation approach

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
- Improve feature detection by setting and checking attribute value
- Avoid memory leak by not creating unused blob URLs
- Remove unsupported csp attribute when falling back to meta tags
- CodeQL verification: 0 alerts

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 5, 2025

@copilot Chrome supports csp on the iframe element (https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/csp) I would like to make sure that we use that as a priority, and if not availab...

Implemented iframe csp attribute with fallback to meta tags in commits 484fb76 and 0c13265.

The implementation:

  • Prioritizes iframe csp attribute (set before src per HTML spec)
  • Feature detection: sets attribute and verifies it persists
  • Falls back to CSP meta tag injection for unsupported browsers
  • Applied to both coordinator and renderer iframes

The demo shows fallback in action since the current browser environment doesn't support the iframe csp attribute, but the code will use it when available (Chrome/Edge with flag enabled).

Demo Screenshot

Copilot AI changed the title Add Content Security Policy support with provider-aware defaults Add Content Security Policy support with iframe csp attribute priority Dec 5, 2025
@PaulKinlan
Copy link
Owner

@copilot only the co-ordinator should be able to talk to the LLM (google in this case), therefore that part of the CSP should not be sent through to inner iframe UNLESS it was also included in the csp attribute on the custom element.

Copilot AI and others added 2 commits December 5, 2025 15:45
- Coordinator gets CSP with LLM API connect-src (Gemini/Chrome AI)
- Renderer gets CSP with connect-src 'none' (blocks external connections)
- Custom CSP attribute still applies to both iframes
- Addresses security concern: only coordinator should access LLM API

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
- Cache both coordinator and renderer CSP to avoid redundant computation
- Add comments explaining custom CSP applies to both layers (user control)
- Clarify security boundary: renderer blocked from external APIs by default

Co-authored-by: PaulKinlan <45510+PaulKinlan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 5, 2025

@copilot only the co-ordinator should be able to talk to the LLM (google in this case), therefore that part of the CSP should not be sent through to inner iframe UNLESS it was also included in the csp...

Implemented CSP separation in commits 7e380ea and b85990e.

Changes:

  • Coordinator CSP includes provider-specific connect-src (e.g., https://generativelanguage.googleapis.com for Gemini)
  • Renderer CSP gets connect-src 'none' - blocks all external connections
  • Custom CSP attribute applies to both layers (gives users full control)

Security boundary: Only the coordinator can access the LLM API. The renderer iframe is isolated from making any external connections unless explicitly allowed via custom CSP.

Demo

Copilot AI changed the title Add Content Security Policy support with iframe csp attribute priority Add Content Security Policy support with layered iframe isolation Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add CSP

2 participants