For the complete documentation index, see llms.txt. Prefer markdown by appending .md to documentation URLs or sending Accept: text/markdown.

Content scripts & messaging

Keep content scripts isolated from page JavaScript, narrow match patterns, and treat extension messages as untrusted input.

Content scripts run on web pages in an isolated world: they can see the DOM, but they do not share the page’s JavaScript scope. That isolation is a core security boundary - do not punch holes in it casually.

Match patterns

Define content scripts with the narrowest matches that still work:

src/app/content/index.ts
export default defineContentScript({
  matches: ["https://app.example.com/*"],
  async main(ctx) {
    // ...
  },
});

Avoid <all_urls> unless the product truly requires it (same store and security concerns as host permissions).

See Content scripts for CSUI and layout details.

Isolation rules

  • Never put API secrets, webhook secrets, or raw session tokens into page-injected scripts
  • Prefer extension pages (popup, options, sidepanel) for privileged UI
  • If you must bridge to window, expose the smallest API and assume the page can call it
  • Sanitize anything you read from the DOM before sending it to your API

Messaging

Popup, background, and content scripts talk through typed messaging. Treat every message like an external request:

  1. Validate the message shape (Zod or equivalent)
  2. Confirm the sender context when the action is sensitive
  3. Perform privileged work in the background (or via your Hono API), not in the content script
  4. Do not trust a content script claiming userId / organizationId / isAdmin without server verification
Pattern
// Background: validate, then call the protected API with the real session

See Messaging for the WXT helpers.

XSS and page trust

A compromised or hostile page can try to:

  • Trick your CSUI into displaying phishing chrome
  • Spam your message handlers
  • Exfiltrate data you write into the DOM

Keep secrets out of the DOM, keep privileged actions server-side, and rate-limit / validate handlers.

Practical rules

  • Default to no content script until a feature needs the page
  • Prefer activeTab + scripting on user gesture over always-on scripts
  • Review match patterns in the same PR as the script
  • Capture errors with monitoring without logging cookies or tokens

How is this guide?

Last updated on

On this page

Ship your startup everywhere. In minutes.Try TurboStarter