{"id":662,"library":"nh3","title":"nh3 HTML Sanitizer","description":"nh3 is a Python binding to the Ammonia HTML sanitizer Rust crate, providing fast and configurable whitelist-based HTML sanitization. It is notably faster than pure-Python alternatives like `Bleach`, which it largely replaces since `html5lib` became unmaintained. The library is actively maintained, with its current version 0.3.4, and receives regular updates to both the Python bindings and its underlying Rust components.","status":"active","version":"0.3.4","language":"python","source_language":"en","source_url":"https://github.com/messense/nh3","tags":["html-sanitizer","security","rust-bindings","xss-prevention","html"],"install":[{"cmd":"pip install nh3","lang":"bash","label":"Install nh3"}],"dependencies":[],"imports":[{"symbol":"clean","correct":"from nh3 import clean"},{"symbol":"Cleaner","correct":"from nh3 import Cleaner"}],"quickstart":{"code":"import nh3\n\n# Basic sanitization\nunclean_html = \"<b><img src='' onerror='alert(\\'hax\\')'>XSS?</b><script>alert('malicious')</script><p>Hello</p>\"\ncleaned_html = nh3.clean(unclean_html)\nprint(f\"Cleaned HTML: {cleaned_html}\")\n\n# Customizing allowed tags\ncustom_cleaned = nh3.clean(unclean_html, tags={\"b\", \"p\"})\nprint(f\"Custom cleaned (b, p only): {custom_cleaned}\")\n\n# Using Cleaner for reusable configuration\nmy_cleaner = nh3.Cleaner(\n    tags={\"b\", \"i\", \"p\"},\n    attributes={\n        \"a\": {\"href\"},\n        \"img\": {\"src\"}\n    },\n    url_schemes={\"http\", \"https\"}\n)\nreusable_cleaned = my_cleaner.clean(\"<a href='javascript:alert(\\\"xss\\\")'>Click</a><b>Bold</b><i>Italic</i><script>evil</script>\")\nprint(f\"Reusable cleaner output: {reusable_cleaned}\")","lang":"python","description":"Sanitize an HTML fragment using the default configuration, then customize allowed tags, and finally demonstrate creating a reusable `Cleaner` instance with specific rules for tags, attributes, and URL schemes."},"warnings":[{"fix":"Review `nh3` documentation, especially for `tags`, `attributes`, and `url_schemes` parameters, to match your desired sanitization policy. Consider `nh3.Cleaner` for explicit, reusable configurations.","message":"nh3 is a modern replacement for the deprecated `Bleach` library. Users migrating from `Bleach` should note that while APIs are similar, configuration and underlying behavior may differ, requiring careful review of sanitization rules.","severity":"breaking","affected_versions":"All versions (when migrating from Bleach)"},{"fix":"Always explicitly specify the `tags` and `attributes` you want to allow using the `nh3.clean()` function parameters or by configuring an `nh3.Cleaner` instance. For example, `nh3.clean(html, tags={'p', 'b', 'i'}, attributes={'a': {'href'}})` to define a strict whitelist.","message":"The default `nh3.clean()` function allows a relatively broad set of HTML tags (around 75) and attributes. This might be too permissive for many applications and could inadvertently allow potentially unsafe content if not explicitly restricted.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Keep `nh3` up-to-date with the latest releases. Monitor the `nh3` GitHub repository and PyPI for security announcements and new versions.","message":"As `nh3` is a binding to the Rust `ammonia` crate, security vulnerabilities in the underlying Rust library can affect it. Regular updates are necessary to incorporate critical fixes. For example, recent updates addressed `RUSTSEC-2025-0071`.","severity":"breaking","affected_versions":"All versions before 0.3.x (and any future versions with unpatched underlying Rust crate vulnerabilities)"},{"fix":"Implement sanitization in Django form fields (e.g., in `to_python`) or consider using a dedicated package like `django-nh3` (if mature) that provides a sanitized model field. Always sanitize user-provided input *before* saving it to the database.","message":"When integrating with web frameworks like Django, simply calling `nh3.clean()` in templates or view logic may not be sufficient. Unsanitized data might still be saved to the database if sanitization isn't applied at the input (e.g., form field or model field) level.","severity":"gotcha","affected_versions":"All versions (when used in web frameworks without proper integration)"}],"env_vars":null,"last_verified":"2026-05-12T17:32:31.788Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install nh3`","cause":"The 'nh3' library is not installed in your current Python environment, or there is a typo in the import statement.","error":"ModuleNotFoundError: No module named 'nh3'"},{"fix":"Use the `clean` function within the module to sanitize HTML: `nh3.clean(html_string)`","cause":"You are attempting to call the 'nh3' module directly as a function (e.g., `nh3(html_string)`), instead of calling its `clean` function.","error":"TypeError: 'module' object is not callable"},{"fix":"Ensure arguments like `tags`, `clean_content_tags`, and `url_schemes` are passed as Python `set` objects, and `attributes` as a dictionary of `set` objects, as specified in the documentation. For example, `nh3.clean(html_string, tags={'b', 'i'})`","cause":"A parameter in `nh3.clean()`, such as `tags`, `clean_content_tags`, or `url_schemes`, was provided with an incorrect data type (e.g., a list instead of a set).","error":"TypeError: Argument 'tags' must be set, not list"}],"ecosystem":"pypi","meta_description":null,"install_score":80,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"0.3.5","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20.6M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0,"mem_mb":0,"disk_size":"21M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"21M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"22.4M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"22.4M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0,"mem_mb":0,"disk_size":"22M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"22M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"14.3M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"14.3M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0,"mem_mb":0,"disk_size":"14M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"14M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"14.0M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"13.9M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0,"mem_mb":0,"disk_size":"14M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"14M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20.1M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20.1M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.9,"import_time_s":0,"mem_mb":0,"disk_size":"20M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}