---
title: "Insert text into web pages as text from · Agent Wranglers"
url: https://agentwranglers.se/playbook/desktop-apps/browser-extensions/content-script-dom
id: DSK-35
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1167
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Insert text into web pages as text from content scripts

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Browser extensions](https://agentwranglers.se/playbook/desktop-apps/browser-extensions.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: DSK-35
- Level: Recommended
- Chapter: [Browser extensions](https://agentwranglers.se/playbook/desktop-apps/browser-extensions.md)
- Rule: Content scripts put strings into a page with `textContent`, `createElement` and `setAttribute`, never with `innerHTML`, `outerHTML`, `insertAdjacentHTML` or `document.write`. HTML that must go in passes a sanitiser such as DOMPurify first. Controls the user clicks live in the extension's own popup or side panel.
- Check: A lint rule such as `eslint-plugin-no-unsanitized` runs on every content script in CI and fails on an unsanitised HTML sink. A test page with the title `<img src=x onerror=alert(1)>` runs the extension, and no alert fires.
- How: A content script that writes page text, API answers or stored notes as HTML opens a hole on every site the user visits. [Stop cross-site scripting](https://agentwranglers.se/playbook/application-security/input-and-injection/cross-site-scripting.md) describes the attack. Mozilla tells extension authors to insert strings with safe DOM methods and to sanitise any HTML with an up-to-date DOMPurify. It also warns that page scripts can reach buttons or toolbars added to the page. Put such controls in the extension's own UI or in an iframe the page cannot touch. Never call `window.eval()` or read page objects through `wrappedJSObject` and then act on them. Messages the content script sends on follow [treat messages from web pages and content scripts as untrusted](https://agentwranglers.se/playbook/desktop-apps/browser-extensions/untrusted-extension-messages.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
// content.js: the note comes from storage, so it goes in as text
export function showNote(note) {
  const badge = document.createElement('span');
  badge.className = 'ledgerly-note';
  badge.textContent = note.text;
  badge.setAttribute('title', note.author);
  document.body.append(badge);
}
```

### Python example

```python
# test_content_script.py: a hostile page title must not run as script
from playwright.sync_api import sync_playwright

def test_title_is_inserted_as_text(extension_context_dir, extension_path):
    with sync_playwright() as p:
        browser = p.chromium.launch_persistent_context(extension_context_dir, args=[f"--load-extension={extension_path}"])
        page = browser.new_page()
        dialogs = []
        page.on("dialog", lambda dialog: (dialogs.append(dialog.message), dialog.dismiss()))
        page.set_content("<title><img src=x onerror=alert(1)></title><p>Invoice 42</p>")
        page.wait_for_selector(".ledgerly-note")
        assert dialogs == []
```

## Sources

- [Firefox Extension Workshop, Build a secure extension](https://extensionworkshop.com/documentation/develop/build-a-secure-extension/)
- [OWASP Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)

## Related rules

- APS-3 [Escape everything you show](https://agentwranglers.se/playbook/application-security/input-and-injection/cross-site-scripting.md) in Application security
- DSK-16 [Treat messages from web pages and content scripts as untrusted](https://agentwranglers.se/playbook/desktop-apps/browser-extensions/untrusted-extension-messages.md) in Desktop apps and extensions

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/desktop-apps/browser-extensions/content-script-dom">Agent Wranglers desktop apps and extensions playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Expose as few extension files to web pages as you can](https://agentwranglers.se/playbook/desktop-apps/browser-extensions/web-accessible-resources.md)
- Next: [Roll out extension updates in stages](https://agentwranglers.se/playbook/desktop-apps/browser-extensions/extension-staged-rollout.md)
- [Browser extensions](https://agentwranglers.se/playbook/desktop-apps/browser-extensions.md)
