# "HTML Sanitization"
_Path: en/lua/http/html_
> "Sanitize untrusted HTML to prevent XSS attacks. Based on bluemonday."
## Table of Contents
- HTML Sanitization
## Content
# HTML Sanitization
Hello world
') -- 'Hello world
' local xss = policy:sanitize('Hello
') -- 'Hello
' ``` **Returns:** `Policy, error` ### Strict Policy Create a strict policy that removes HTML and returns plain text: ```lua local policy, err = html.sanitize.strict_policy() if err then return nil, err end local text = policy:sanitize('Hello world!
') -- 'Hello world!' ``` **Returns:** `Policy, error` ### Allow Elements Allow specific HTML elements: ```lua local policy, err = html.sanitize.new_policy() if err then return nil, err end policy:allow_elements("p", "strong", "em", "br") policy:allow_elements("h1", "h2", "h3") policy:allow_elements("a", "img") local result = policy:sanitize('Hello world
') -- 'Hello world
' ``` | Parameter | Type | Description | |-----------|------|-------------| | `...` | string | Element tag names | **Returns:** `Policy` ### Allow Attributes Start an attribute rule, then apply it with `on_elements()` or `globally()`: ```lua policy:allow_attrs("href"):on_elements("a") policy:allow_attrs("src", "alt"):on_elements("img") policy:allow_attrs("class", "id"):globally() ``` | Parameter | Type | Description | |-----------|------|-------------| | `...` | string | Attribute names | **Returns:** `AttrBuilder` ### On Specific Elements Allow attributes only on specified elements: ```lua policy:allow_elements("a", "img") policy:allow_attrs("href", "target"):on_elements("a") policy:allow_attrs("src", "alt", "width", "height"):on_elements("img") ``` | Parameter | Type | Description | |-----------|------|-------------| | `...` | string | Element tag names | **Returns:** `Policy` ### On All Elements Allow attributes on every permitted element: ```lua policy:allow_attrs("class"):globally() policy:allow_attrs("id"):globally() ``` **Returns:** `Policy` ### With Pattern Matching Require attribute values to match a regular expression: ```lua -- Only allow hex colors in style local builder, err = policy:allow_attrs("style"):matching("^color:#[0-9a-fA-F]{6}$") if err then return nil, err end builder:on_elements("span") policy:sanitize('Red') -- 'Red' policy:sanitize('Bad') -- 'Bad' ``` | Parameter | Type | Description | |-----------|------|-------------| | `pattern` | string | Go RE2-compatible regular expression | **Returns:** `AttrBuilder, error` ### Standard URLs Enable the standard URL-handling policy. It requires parseable URLs, permits relative URLs plus `mailto`, `http`, and `https`, and adds `rel="nofollow"` to allowed linking elements: ```lua policy:allow_elements("a") policy:allow_attrs("href"):on_elements("a") policy:allow_standard_urls() ``` **Returns:** `Policy` ### URL Schemes Allow specific URL schemes: ```lua policy:allow_url_schemes("https", "mailto") policy:sanitize('OK') -- 'OK' policy:sanitize('XSS') -- 'XSS' ``` | Parameter | Type | Description | |-----------|------|-------------| | `...` | string | Schemes to allow | **Returns:** `Policy` ### Relative URLs Configure whether relative URLs are allowed: ```lua policy:allow_relative_urls(true) policy:sanitize('Link') -- 'Link' ``` | Parameter | Type | Description | |-----------|------|-------------| | `allow` | boolean | Allow relative URLs | **Returns:** `Policy` ### Require Parseable URLs Reject URLs that fail to parse cleanly. With `true`, attribute URLs that the HTML sanitizer cannot parse are stripped instead of passed through. ```lua policy:require_parseable_urls(true) ``` | Parameter | Type | Description | |-----------|------|-------------| | `require` | boolean | Require URLs to be parseable | **Returns:** `Policy` ### Nofollow Links Add `rel="nofollow"` to links: ```lua policy:allow_attrs("href", "rel"):on_elements("a") policy:allow_url_schemes("https") policy:require_parseable_urls(true) policy:require_nofollow_on_links(true) policy:sanitize('Link') -- 'Link' ``` | Parameter | Type | Description | |-----------|------|-------------| | `require` | boolean | Add nofollow | **Returns:** `Policy` ### Noreferrer Links Add `rel="noreferrer"` to links: ```lua policy:require_noreferrer_on_links(true) ``` | Parameter | Type | Description | |-----------|------|-------------| | `require` | boolean | Add noreferrer | **Returns:** `Policy` ### External Links in New Tab Add `target="_blank"` to fully qualified URLs: ```lua policy:allow_attrs("href", "target"):on_elements("a") policy:allow_url_schemes("https") policy:require_parseable_urls(true) policy:add_target_blank_to_fully_qualified_links(true) policy:sanitize('Link') -- 'Link' ``` | Parameter | Type | Description | |-----------|------|-------------| | `add` | boolean | Add target blank | **Returns:** `Policy` When opening untrusted links in a new tab, also enable `require_noreferrer_on_links(true)` to suppress referrer leakage and mitigate opener access. ### Allow Images Permit `
')
-- '
'
```
**Returns:** `Policy`
### Allow Data URI Images
Permit syntactically valid Base64-encoded `gif`, `jpeg`, `png`, `svg+xml`, or `webp` data URI images. The sanitizer validates the media type and Base64 encoding, not the decoded image contents. Data URIs can carry active content, so enable them only for content whose image data you trust:
```lua
policy:allow_elements("img")
policy:allow_attrs("src"):on_elements("img")
policy:allow_data_uri_images()
local input = '| Cell |
| Cell |
Hello
') -- 'Hello
' ``` **Returns:** `Policy` ## Sanitize Apply a policy to an HTML string: ```lua local policy, err = html.sanitize.ugc_policy() if err then return nil, err end policy:require_nofollow_on_links(true) local dirty = 'Hello
' local clean = policy:sanitize(dirty) -- 'Hello
' ``` | Parameter | Type | Description | |-----------|------|-------------| | `html` | string | HTML to sanitize | **Returns:** `string` `sanitize` returns only a string. In runtime `v0.3.32a`, the underlying fragment parser can turn malformed input that it cannot parse into an empty string, and the Lua wrapper cannot distinguish that case from valid input whose content the policy removed. Treat sanitization as output filtering, not input validation; validate required content separately when an empty result matters. ## Errors | Condition | Kind | Retryable | |-----------|------|-----------| | Invalid regex pattern | `errors.INVALID` | no | See [Error Handling](lua/core/errors.md) for working with errors. ## Navigation Previous: "WebSocket Client" (lua/http/websocket) Next: "SQL Database" (lua/storage/sql)