python 39 lines · 5 steps

Sanitizing user HTML with bleach

Whitelist safe tags and attributes, strip everything else, then harden auto-generated links against tabnabbing.

Explained by highlit
1import bleach
2 
3ALLOWED_TAGS = [
4 "a", "b", "strong", "i", "em", "u",
5 "p", "br", "ul", "ol", "li", "blockquote",
6 "code", "pre", "h1", "h2", "h3",
7]
8 
9ALLOWED_ATTRIBUTES = {
10 "a": ["href", "title", "rel"],
11}
12 
13ALLOWED_PROTOCOLS = ["http", "https", "mailto"]
14 
15 
16def sanitize_user_html(raw: str) -> str:
17 cleaned = bleach.clean(
18 raw,
19 tags=ALLOWED_TAGS,
20 attributes=ALLOWED_ATTRIBUTES,
21 protocols=ALLOWED_PROTOCOLS,
22 strip=True,
23 strip_comments=True,
24 )
25 
26 linker = bleach.linkifier.Linker(
27 callbacks=[_force_noopener],
28 skip_tags=["pre", "code"],
29 )
30 return linker.linkify(cleaned)
31 
32 
33def _force_noopener(attrs, new=False):
34 href_key = (None, "href")
35 if href_key not in attrs:
36 return attrs
37 attrs[(None, "rel")] = "nofollow noopener noreferrer"
38 attrs[(None, "target")] = "_blank"
39 return attrs
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1A whitelist of allowed tags and attributes is safer than trying to blacklist dangerous markup.
  2. 2Restricting URL protocols blocks javascript: and data: vectors that survive tag filtering.
  3. 3Auto-generated links should carry rel=noopener noreferrer to prevent reverse-tabnabbing attacks.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Sanitizing user HTML with bleach — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code