For the complete documentation index, see llms.txt. Prefer markdown by appending.mdto documentation URLs or sendingAccept: 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:
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:
- Validate the message shape (Zod or equivalent)
- Confirm the sender context when the action is sensitive
- Perform privileged work in the background (or via your Hono API), not in the content script
- Do not trust a content script claiming
userId/organizationId/isAdminwithout server verification
// Background: validate, then call the protected API with the real sessionSee 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