Skip to main content

PolyXML SafeXML

SafeXML 🛡️

The memory-safe, GIL-free, ultra-fast XML parser and drop-in defusedxml successor built in Rust.

CI PyPI version Python versions Coverage: 100% Rust: 100% Safe GIL: Detached License: MIT


⚡ The Case for SafeXML: Why DefusedXML is Obsolete

For over a decade, Python developers relied on defusedxml to protect against XML bombs. But defusedxml is fundamentally a legacy wrapper around CPython's 1990s-era C pyexpat engine. In modern Python (>=3.12), defusedxml has become a security liability and performance bottleneck:

1. Immune to C Memory Corruption (CVE Hell)

defusedxml is just a Python-level monkeypatch on top of C libexpat. When libexpat suffers from integer overflows, heap buffer overflows, or use-after-free bugs, defusedxml cannot protect you. Between 2022 and 2026 alone, libexpat was hit by a barrage of critical CVEs:

  • CVE-2024-45490, CVE-2024-45491, CVE-2024-45492: Integer overflows in XML parsing causing heap corruption.
  • CVE-2023-52425: Denial of service through entity expansion parser state corruption.
  • CVE-2022-25235, CVE-2022-25236, CVE-2022-23852: Malformed namespace and character encoding heap buffer crashes.

SafeXML is written in 100% memory-safe Rust using quick-xml and PyO3. There is zero C code, zero raw memory pointers, zero heap corruption, and zero use-after-free risk.

2. True GIL Release for Modern Multi-Threaded Services

When parsing XML inside high-concurrency web frameworks (FastAPI, Django, Flask, Celery, gRPC), defusedxml holds Python's Global Interpreter Lock (GIL). Ten worker threads parsing XML become serialized into a single-core crawl.

SafeXML detaches the Python GIL during parsing (py.detach(|| ...)). Rust processes, validates, and decodes the XML stream completely in parallel across all CPU cores, unlocking linear multi-core speedup.

3. Defeats Modern XML Attacks That defusedxml Misses

defusedxml only guards against traditional DTD and entity expansions. It completely misses modern XML attack vectors:

  • Input Size Bounding (CWE-400): Unbounded source streams exhaust host memory before parsing completes. SafeXML enforces max_input_size (default 256MB) with bounded reading.
  • Element Count Bounding (CWE-400): Millions of sibling elements bypass recursion depth limits. SafeXML enforces max_elements (default 5,000,000).
  • Attribute Flood / Attribute Hash DoS (CWE-400): Attackers submit elements with 100,000 attributes. defusedxml constructs a massive Python dictionary, causing quadratic memory overhead. SafeXML enforces max_attributes (default 1,000).
  • Giant Attribute Value Bombs (CWE-400): A single 50MB attribute value crashes memory. defusedxml does not inspect attribute lengths. SafeXML enforces max_attribute_size (default 10MB).
  • Comment Amplification Bombs: Millions of comments or giant comment streams exhaust parser memory. SafeXML enforces max_comment_size (default 10MB).
  • Tag Name Memory Bombs: Gigantic element tag names consume unbounded memory during string interning. SafeXML enforces max_name_size (default 1,024 chars).
  • Null Byte Injection: Embedded null bytes (\0) in tag or attribute names cause C-string truncation attacks downstream in databases and auth services. SafeXML strictly rejects null bytes.

🥊 Comprehensive Attack Surface & Feature Matrix

Security / Feature Matrix safexml (Rust) defusedxml (Python + C) lxml (C libxml2) xml.etree (Python stdlib)
Billion Laughs / Exponential Entity Bomb 🛡️ BLOCKED 🛡️ BLOCKED ⚠️ Config-dependent ❌ VULNERABLE
Quadratic Blowup Entity Attack 🛡️ BLOCKED 🛡️ BLOCKED ⚠️ Config-dependent ❌ VULNERABLE
External Entity (XXE) / SSRF 🛡️ BLOCKED 🛡️ BLOCKED ⚠️ Config-dependent ❌ VULNERABLE
External DTD Retrieval 🛡️ BLOCKED 🛡️ BLOCKED ⚠️ Config-dependent ❌ VULNERABLE
Document Size Bounding 🛡️ BLOCKED (max_input_size) ❌ Unbounded read ⚠️ Config-dependent ❌ Unbounded read
Element Count Bounding 🛡️ BLOCKED (max_elements) ❌ Unbounded ❌ Unbounded ❌ Unbounded
Attribute Flood / Memory DoS (CWE-400) 🛡️ BLOCKED (max_attributes) ❌ VULNERABLE ❌ VULNERABLE ❌ VULNERABLE
Giant Attribute Value Bomb (CWE-400) 🛡️ BLOCKED (max_attribute_size) ❌ VULNERABLE ❌ VULNERABLE ❌ VULNERABLE
Tag Name Memory Bomb 🛡️ BLOCKED (max_name_size) ❌ VULNERABLE ❌ VULNERABLE ❌ VULNERABLE
Comment Amplification Bomb 🛡️ BLOCKED (max_comment_size) ❌ VULNERABLE ❌ VULNERABLE ❌ VULNERABLE
Null Byte Identifier Injection 🛡️ BLOCKED ❌ Truncated / Allowed ❌ Truncated / Allowed ❌ Truncated / Allowed
Immune to C-Level Memory Corruption 🛡️ YES (Safe Rust) ❌ No (libexpat CVEs) ❌ No (libxml2 CVEs) ❌ No (libexpat CVEs)
Releases Python GIL (Parallel Scaling) ⚡ YES (py.detach) ❌ No (Blocks GIL) ⚠️ Partial ❌ No (Blocks GIL)
PEP 561 Type Annotations (py.typed) ✅ YES ❌ No ⚠️ Separate stub ⚠️ Standard library
Rich / Structured Logging Compatible ✅ YES ❌ Missing args ✅ Yes ✅ Yes
ElementTree indent() Built-in ✅ YES ❌ Missing ✅ Yes ✅ Yes
Modern Python Target 🐍 Python >= 3.12 🏚️ Python 2 / Legacy 🐍 All 🐍 Standard library

🚀 Benchmarks: SafeXML vs DefusedXML

Benchmarks run on Linux x86_64, Python 3.12.14, comparing safexml against defusedxml and stdlib xml.etree:

1. Single-Threaded Throughput & Latency

Small Workload (~1 KB XML document):
  SafeXML (Rust):    67.2 µs | 14,879 ops/sec  [1.63x FASTER (+62.9% throughput)] ⚡
  defusedxml:       109.5 µs |  9,133 ops/sec  [Baseline]

Large Workload (~500 KB, 5,000 items):
  SafeXML (Rust):    42.3 ms |    23.6 ops/sec  [1.23x FASTER (+23.3% throughput)] ⚡
  defusedxml:        52.2 ms |    19.2 ops/sec  [Baseline]

2. Multi-Threaded Concurrency (GIL-Release Benchmark)

Under concurrent.futures.ThreadPoolExecutor simulating concurrent API requests:

Worker Threads defusedxml Throughput SafeXML Throughput Real-World Concurrency Speedup
2 Workers 547.6 docs/sec 779.9 docs/sec 1.42x FASTER 🚀
4 Workers 579.8 docs/sec 828.8 docs/sec 1.43x FASTER 🚀
8 Workers 624.1 docs/sec 838.6 docs/sec 1.34x FASTER 🚀

Under heavy multi-threaded workloads, defusedxml saturates the GIL and stalls. safexml frees Python threads to process requests in parallel.


✨ Modern Standard Library Compatibility & Developer Ergonomics

safexml provides complete compatibility with Python's standard xml.etree.ElementTree while delivering modern developer ergonomics:

  • Structured Tracebacks: All exceptions populate standard args and message properties, rendering cleanly in rich, IPython, and logging pipelines.
  • PEP 561 Typing: Ships with inline py.typed markers and comprehensive type annotations for mypy and pyright.
  • ElementTree indent(): Full support for XML pretty-printing and tree indentation matching Python 3.9+ standard library APIs.
  • Element Class Re-export: Element is exported directly from safexml.ElementTree and top-level safexml.
  • Namespace Registration: register_namespace() is supported for deterministic namespace prefix serialization.
  • Signature Parity: fromstring() accepts standard library keyword arguments including parser=.
  • Non-Destructive Defusing: defuse_stdlib() patches standard library parsers without breaking third-party libraries (e.g. openpyxl, xmlschema) or corrupting Element identity.

📦 Installation

Prebuilt abi3 binary wheels are available on PyPI for Linux, macOS (Apple Silicon & Intel), and Windows:

pip install safexml

Requirements: Python >= 3.12.


💡 Quickstart: 10-Second Migration

1. Direct Drop-in Replacement for defusedxml.ElementTree

Simply update your import:

# Before:
# import defusedxml.ElementTree as ET

# After:
import safexml.ElementTree as ET

# 100% identical API, backed by Rust:
root = ET.fromstring("<catalog><item id='1'>Safe XML</item></catalog>")
print(root.tag)  # "catalog"
print(root[0].text)  # "Safe XML"

# Built-in pretty-printing
ET.indent(root)
print(ET.tostring(root, encoding="unicode"))

2. Drop-in Replacement for defusedxml.minidom and defusedxml.sax

# minidom drop-in
from safexml import minidom

doc = minidom.parseString("<catalog><item id='1'>Safe XML</item></catalog>")
print(doc.documentElement.tagName)  # "catalog"

# SAX drop-in
from safexml import sax
from xml.sax.handler import ContentHandler


class CustomHandler(ContentHandler):
    def startElement(self, name, attrs):
        print(f"Element: {name}")


sax.parseString("<root><item/></root>", CustomHandler())

3. Global Non-Destructive Stdlib Defusing

If you have third-party dependencies (like openpyxl, boto3, or saml2) using Python's standard xml.etree.ElementTree, xml.dom.minidom, or xml.sax, you can secure your entire application runtime with one call:

import safexml

# Safely patches xml.etree.ElementTree, xml.dom.minidom, and xml.sax
safexml.defuse_stdlib()

4. Catching Security Violations

import safexml.ElementTree as ET
from safexml.common import (
    DefusedXmlException,
    DTDForbidden,
    EntitiesForbidden,
    ExternalReferenceForbidden,
)

# 1. Billion Laughs / Exponential Entity Bomb
try:
    ET.fromstring("""<!DOCTYPE bomb [
        <!ENTITY a "1234567890">
        <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;">
    ]><bomb>&a;</bomb>""")
except EntitiesForbidden as exc:
    print(f"Blocked entity expansion: {exc.name}")

# 2. External DTD / XXE / SSRF
try:
    ET.fromstring("""<!DOCTYPE root SYSTEM "http://attacker.com/evil.dtd"><root/>""")
except ExternalReferenceForbidden as exc:
    print(f"Blocked external reference: {exc.sysid}")

# 3. Attribute Flood DoS (CWE-400)
try:
    # Restrict attributes to 5 per element (default: 1,000)
    ET.fromstring("<root a1='1' a2='2' a3='3' a4='4' a5='5' a6='6'/>", max_attributes=5)
except DefusedXmlException as exc:
    print(f"Blocked attribute flood: {exc}")

# 4. Giant Tag Name Bomb
try:
    ET.fromstring(f"<{'A' * 2000}/>", max_name_size=1024)
except DefusedXmlException as exc:
    print(f"Blocked oversized tag: {exc}")

🧪 W3C XML Conformance Validation

SafeXML is rigorously verified against the official W3C XML Conformance Test Suite (XMLTS 20130923) across all 2,585 test cases:

  • 100.00% Malformed Rejection Rate: Zero discrepancies across all applicable XML 1.0 test cases. All non-well-formed documents are strictly rejected with zero panics or crashes.
  • Security Policy Enforcement: Explicit exclusions for external entity references (forbid_external=True) and general entity expansions (forbid_entities=True) block XXE and exponential blowup while preserving standard conformance.
  • Automated Verification: Integrated manifest runner in scripts/run_w3c_conformance.py and automated pytest suite.

For the complete breakdown and specification details, see the W3C Conformance Report.


🏭 Industrial Schema & Adversarial Payload Hardening

SafeXML is validated against real-world enterprise schemas and payloads aggregated in polyxml/polyxml-schema-corpus across 18 critical industries:

  • Battle-Tested Domains: SAML 2.0 Identity, AS4 ebMS3 B2B Messaging, ISDA FpML 5.12 Derivatives, ISO 20022 SEPA Banking, HL7 FHIR R4 & CDA R2.1 Healthcare, OASIS UBL 2.1 Invoicing, NATO/DoD UCI 2.5 Defense, and ICAO/FAA FIXM 4.0 Aviation.
  • SAML & AS4 Adversarial Hardening: Zero-trust defense against XXE injection, exponential entity expansion, quadratic blowup, and attribute-flood DoS payloads injected directly into authentication tokens and SOAP envelopes.
  • Large-Document Throughput: Up to 43 MB/s single-threaded throughput and 1.4x to 1.66x multi-threaded concurrency speedup over defusedxml on multi-megabyte schemas.

For benchmark data and attack reproduction suites, see the Industrial Validation Report.


⚡ Continuous Structure-Aware Fuzzing & Sanitizers

SafeXML incorporates continuous fuzz testing to guarantee memory safety and zero panics across arbitrary inputs and parameter configurations:

  • Structure-Aware libFuzzer: Randomized ParseOptions fuzz target (fuzz/fuzz_targets/fuzz_parser.rs) exploring permutations of depth limits, attribute bounds, and DTD permissions.
  • XML Syntax Dictionary: Seeded with fuzz/xml.dict containing XML grammar tokens, DTD specifiers, namespace declarations, and known attack strings.
  • Nightly Sanitizer Pipeline: Automated GitHub Actions workflow (.github/workflows/fuzz.yml) running libFuzzer under AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan) with crash artifact archiving.
  • Google OSS-Fuzz: Integration manifests prepared in oss-fuzz/ for 24/7 continuous distributed cluster fuzzing.

🏗️ Architectural Distinction: safexml vs polyxml

Both projects are maintained by the PolyXML organization:

Feature safexml polyxml
Primary Role Untyped DOM / ElementTree drop-in replacement Data-Binding & Serde Engine (Schema-driven)
Output Type xml.etree.ElementTree.Element Typed Python objects (Dataclasses, Pydantic, Attrs)
Primary Use Legacy migrations, SAML, SVG, Office files, arbitrary XML High-throughput APIs, SOAP, microservices, typed pipelines
Security Focus Comprehensive attack surface defense & resource bounding Strict schema validation & zero-copy Rust deserialization

📄 License

MIT License. Engineered with pride under the PolyXML organization by Bailey Nguyen.

Metadata

Release files for safexml 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for safexml 1.1.0
File Size Uploaded Provenance
safexml-1.1.0.tar.gz 271.0 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for safexml 1.1.0
File
safexml-1.1.0-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
safexml-1.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.12 abi3 Linux glibc 2.17+ x86-64 Details
safexml-1.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.12 abi3 Linux glibc 2.17+ ARM64 Details
safexml-1.1.0-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details
safexml-1.1.0-cp312-abi3-macosx_10_12_x86_64.whl CPython 3.12 abi3 macOS 10.12+ x86-64 Details

Total release size: 2.2 MB

Release files / safexml-1.1.0.tar.gz

Download URL safexml-1.1.0.tar.gz
Size 271.0 kB
Tags Source
SHA-256 checksum
How to use checksums
28d72736a3037c42ecd666b40883b572937633d8674c43ff489dc0c8f96097a8
BLAKE2b-256 checksum
How to use checksums
84015df1dbeb2aba0a4160105c3dd950cb0afffe175abdd27e7130e12d35f676
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / safexml-1.1.0-cp312-abi3-win_amd64.whl

Download URL safexml-1.1.0-cp312-abi3-win_amd64.whl
Size 318.9 kB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
bd3579282a67a5cd212f18ea29baf491e617f1b092962bd4707716a9f558d684
BLAKE2b-256 checksum
How to use checksums
bd70ed054b3726bd0295ca19245c0b09e681b44e5232ad93dce89b179ab5fd06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / safexml-1.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL safexml-1.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 400.6 kB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
ff893623e90ab715e9e070851aaa0759d756224ccba3acce17605a2ec2836529
BLAKE2b-256 checksum
How to use checksums
1c34aea3eec502533141a29c34149bcf2076c75d65f34511b178c49cb9d34454
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / safexml-1.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL safexml-1.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 390.1 kB
Tags CPython 3.12 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
cc511d30bffc80326888fbfe91ab27a92ac8ef3e2b6341f7e65faf9488b516ed
BLAKE2b-256 checksum
How to use checksums
6eaae596087f9c3e376801fc69f9acff116dc349ad7cd7827212458e23252bbb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / safexml-1.1.0-cp312-abi3-macosx_11_0_arm64.whl

Download URL safexml-1.1.0-cp312-abi3-macosx_11_0_arm64.whl
Size 382.0 kB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
516efb3ab263a041526b0439e11e63e513ca583f29020da60c43f39794d9805f
BLAKE2b-256 checksum
How to use checksums
67402d777392e9529fbb5c65d1192dc8398c7ae44b167b874cfadc1760a4c2fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / safexml-1.1.0-cp312-abi3-macosx_10_12_x86_64.whl

Download URL safexml-1.1.0-cp312-abi3-macosx_10_12_x86_64.whl
Size 393.7 kB
Tags CPython 3.12 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
7b00dd4c0fc8d0fe36a2c861c9949c553e501869b739737d6dc47b0969d84aea
BLAKE2b-256 checksum
How to use checksums
808a452fceef0bf7ca832160b9b92c6debce168be873f3d154ee29029503b2ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Security for safexml 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for safexml-1.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page