---
title: "Escape everything you show · Agent Wranglers"
url: https://agentwranglers.se/playbook/adversarial-testing/injection/cross-site-scripting
updated: 2026-10-20
licence: "All rights reserved"
---

# Escape everything you show

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Injection](https://agentwranglers.se/playbook/adversarial-testing/injection)
- Rule: Escape untrusted text for the place it lands in a page, and back it up with a strict Content Security Policy.
- How: Use a template system that escapes by default, such as Jinja2, Twig, Razor or React. Avoid its raw output switch, such as `|safe` or `dangerouslySetInnerHTML`. In the browser, set `textContent`, not `innerHTML`. Clean rich text with a sanitiser such as DOMPurify. Allow only `http:` and `https:` in links that users supply, because escaping does not stop a `javascript:` link. Block inline scripts with a [Content Security Policy](https://agentwranglers.se/playbook/website/security).
- Check: Put `<b>PENTEST</b>` and `"><svg onload=alert('PENTEST')>` in every field that shows up again, such as names, reviews and search terms. Put `javascript:alert('PENTEST')` in every link field, such as a website address. The page shows the text as typed, runs nothing and refuses the link. The page's `Content-Security-Policy` header has a `script-src` without `'unsafe-inline'`.

Example:

```js
// Bad
el.innerHTML = review.text;
// Good
el.textContent = review.text;
```

```python
# Python: escape before building HTML by hand (Jinja2 and Django templates do this for you)
from markupsafe import escape
html = f"<p>{escape(review_text)}</p>"
```

```php
// PHP
echo '<p>' . htmlspecialchars($review, ENT_QUOTES, 'UTF-8') . '</p>';
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers security testing playbook: https://agentwranglers.se/playbook/adversarial-testing/injection/cross-site-scripting`.

- Previous: [Use parameterised queries](https://agentwranglers.se/playbook/adversarial-testing/injection/sql-injection)
- Next: [Never pass input to a shell](https://agentwranglers.se/playbook/adversarial-testing/injection/command-injection)
- [Injection](https://agentwranglers.se/playbook/adversarial-testing/injection)
