markupsafe
Escapes untrusted strings for safe use in HTML and XML markup, preventing injection attacks in templated output.
Repository Health
Technical Analysis
MarkupSafe implements a Markup string type that escapes special HTML/XML characters (&, <, >, ', ") so untrusted input can be embedded in a page without opening the door to injection attacks. The escape() function converts any value to a Markup instance with the dangerous characters replaced by their entity equivalents, while Markup itself is a str subclass whose methods (concatenation, %-formatting, .format(), .join(), and more) automatically escape any new content mixed in, so a value marked safe stays safe through further string operations.
As the escaping engine underneath Jinja and Flask, MarkupSafe sees enormous real-world usage — hundreds of millions of downloads a week — while staying tiny and dependency-free. Performance-critical paths are implemented as a C extension (_speedups.c) with a pure-Python fallback (_native.py) for platforms where the extension can’t be built, so the same API works everywhere without sacrificing speed where it matters.
What You Get
- A
Markupclass — astrsubclass that marks its contents as pre-escaped/safe for HTML or XML output - An
escape()function that HTML-escapes any input (or delegates to an object’s__html__()method) and returns aMarkupinstance - Escape-aware string operations — concatenation,
%formatting,.format()/.format_map(),.join(),.replace(), and more — that automatically escape newly introduced content escape_silent()for safely handlingNonevalues without producing the literal string “None”soft_str()to convert non-string values tostrwhile preserving already-safeMarkupinstances- A compiled C extension for fast escaping with a transparent pure-Python fallback
Common Use Cases
- Escaping user-submitted text before rendering it inside HTML templates (Jinja, Flask, or custom renderers)
- Building template engines or template-like string composition where mixed safe/unsafe content needs consistent escaping
- Preventing cross-site scripting (XSS) when interpolating dynamic values into HTML fragments or email bodies
- Marking trusted, pre-sanitized HTML (e.g. from a WYSIWYG editor) as safe so it isn’t double-escaped
- Formatting HTML strings with
%-style or.format()interpolation where every substituted value must be escaped automatically
Under The Hood
Architecture
The public surface lives entirely in src/markupsafe/__init__.py: a module-level escape() function and a Markup class that subclasses str. escape() special-cases plain str inputs for speed, defers to an object’s __html__() method when present (the convention shared with Jinja and Flask), and otherwise stringifies and escapes the value, always returning a Markup instance. Markup overrides every str method that can introduce new content — __add__, __radd__, __mod__, .join(), .format(), .replace(), .split(), and more — routing each argument through escape() before delegating to the underlying str implementation, and wrapping the result back in Markup. This closes the obvious escape hatches: once a value is wrapped, ordinary string operations can’t silently reintroduce unescaped content. The actual character substitution is isolated behind a single _escape_inner(s) function, imported first from a compiled _speedups C extension and falling back to an equivalent pure-Python implementation in _native.py via a try/except import — a two-tier strategy that keeps the public API identical regardless of which backend is active.
Tech Stack
A pure standard-library implementation with zero runtime dependencies: string.Formatter is subclassed (EscapeFormatter) to make .format()/.format_map() escape-aware, and html.unescape backs the unescape() helper. The performance-sensitive escape loop is implemented twice — once in C (src/markupsafe/_speedups.c, built via setuptools as a compiled extension distributed as platform wheels) and once in plain Python (_native.py) — so the package works even where no C toolchain or matching wheel is available. Packaging uses pyproject.toml with a setuptools>=77 build backend, uv for dependency/lock management (uv.lock), and cibuildwheel configuration for cross-platform wheel builds including free-threaded CPython targets.
Code Quality
Tests live under tests/ (test_markupsafe.py, test_escape.py, test_leak.py, test_exception_custom_html.py) and are run with pytest, parametrized heavily to cover interpolation, formatting, and edge cases like custom __html__ objects; a dedicated test_leak.py checks for reference leaks in the C extension. The codebase is fully typed (py.typed marker present) and checked with both mypy --strict and pyright, linted and auto-fixed with ruff (bugbear, pyflakes, isort, pyupgrade rules enabled), and enforced via pre-commit hooks. GitHub Actions workflows (tests.yaml, pre-commit.yaml, publish.yaml) run the test matrix and style checks on every change, and tox orchestrates testing across Python 3.10 through 3.14 (including free-threaded builds) plus a dedicated parallel environment for thread-safety checks.
What Makes It Unique
MarkupSafe’s distinguishing choice is treating “safe for HTML” as a first-class string subtype rather than a convention or a manually-called sanitizer function — because Markup overrides the mutating string methods themselves, safety composes correctly through ordinary string operations instead of requiring every call site to remember to escape. Combined with the __html__() protocol, this lets template engines, ORMs, and any object with HTML-rendering logic interoperate through a shared, implicit contract. The dual C/pure-Python backend is a pragmatic rather than novel design, but it lets a library used on the hot path of nearly every Jinja/Flask request stay both universally installable and fast.
Used by 9 apps in this directory
Agno
Devops · AI Development · Automation
Build, run, and manage agent platforms with a full production stack — SDK, runtime, and control plane included.
argilla
AI Development · Data Engineering
Collaborate on high-quality AI training data with a self-hosted annotation platform built for LLMs, NLP, and multimodal models.
GPT Researcher
Productivity · AI Assistants
The pioneering open-source autonomous AI agent that conducts deep, multi-source research and produces citation-backed reports exceeding 2,000 words — faster and more reliably than any human researcher.
Helicone
Monitoring · AI Development · Analytics
An open-source AI gateway and LLM observability platform that routes requests to 100+ models while logging cost, latency, and full traces for every call.
knowhere
AI Development · Developer Tools
Transform messy, unstructured documents into persistent, navigable memory that AI agents can actually use.
LibrePhotos
File Storage
Self-hosted photo library with AI-powered face recognition, semantic search, and automatic event albums — no cloud required.
OSV.dev
Security
Google's open-source vulnerability database that maps CVEs to exact package versions across 50+ ecosystems with a public API and data dumps.
Redash
Analytics · Data Engineering
Redash lets anyone connect to 35+ SQL and NoSQL data sources, write a query in the browser, and turn the result into a shared dashboard — no separate BI suite required.
Taiga Back
Project Management · Developer Tools
Self-hosted agile project management backend with Scrum, Kanban, issue tracking, and a full REST API — built on Django and PostgreSQL.