Your message dated Sat, 11 Jul 2026 10:32:48 +0000
with message-id <[email protected]>
and subject line Released in 13.6
has caused the Debian Bug report #1141370,
regarding trixie-pu: package python-xmltodict/0.13.0-1.1~deb13u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1141370: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1141370
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:python-xmltodict
User: [email protected]
Usertags: pu

  * CVE-2025-9375: XML Injection (Closes: #1113825)
diffstat for python-xmltodict-0.13.0 python-xmltodict-0.13.0

 changelog                                                               |   14 
 patches/0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch |  105 
++++++
 patches/0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch |  170 
++++++++++
 patches/0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch |   50 
++
 patches/series                                                          |    3 
 5 files changed, 342 insertions(+)

diff -Nru python-xmltodict-0.13.0/debian/changelog 
python-xmltodict-0.13.0/debian/changelog
--- python-xmltodict-0.13.0/debian/changelog    2022-08-30 00:16:25.000000000 
+0300
+++ python-xmltodict-0.13.0/debian/changelog    2026-07-03 17:27:34.000000000 
+0300
@@ -1,3 +1,17 @@
+python-xmltodict (0.13.0-1.1~deb13u1) trixie; urgency=medium
+
+  * Non-maintainer upload.
+  * Rebuild for trixie.
+
+ -- Adrian Bunk <[email protected]>  Fri, 03 Jul 2026 17:27:34 +0300
+
+python-xmltodict (0.13.0-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2025-9375: XML Injection (Closes: #1113825)
+
+ -- Adrian Bunk <[email protected]>  Sun, 28 Jun 2026 20:26:05 +0300
+
 python-xmltodict (0.13.0-1) unstable; urgency=medium
 
   * New upstream version 0.13.0
diff -Nru 
python-xmltodict-0.13.0/debian/patches/0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch
 
python-xmltodict-0.13.0/debian/patches/0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch
--- 
python-xmltodict-0.13.0/debian/patches/0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch
      1970-01-01 02:00:00.000000000 +0200
+++ 
python-xmltodict-0.13.0/debian/patches/0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch
      2026-06-28 20:17:51.000000000 +0300
@@ -0,0 +1,105 @@
+From 6592b0e2350ffc0d280f379f2188712ac0d2f4c7 Mon Sep 17 00:00:00 2001
+From: Martin Blech <[email protected]>
+Date: Thu, 4 Sep 2025 17:25:39 -0700
+Subject: Prevent XML injection: reject '<'/'>' in element/attr names (incl.
+ @xmlns)
+
+* Add tests for tag names, attribute names, and @xmlns prefixes; confirm attr 
values are escaped.
+---
+ tests/test_dicttoxml.py | 32 ++++++++++++++++++++++++++++++++
+ xmltodict.py            | 20 +++++++++++++++++++-
+ 2 files changed, 51 insertions(+), 1 deletion(-)
+
+diff --git a/tests/test_dicttoxml.py b/tests/test_dicttoxml.py
+index 7fc2171..c0549e8 100644
+--- a/tests/test_dicttoxml.py
++++ b/tests/test_dicttoxml.py
+@@ -213,3 +213,35 @@ xmlns:b="http://b.com/";><x 
a:attr="val">1</x><a:y>2</a:y><b:z>3</b:z></root>'''
+         expected_xml = '<?xml version="1.0" encoding="utf-8"?>\n<x>false</x>'
+         xml = unparse(dict(x=False))
+         self.assertEqual(xml, expected_xml)
++
++    def test_rejects_tag_name_with_angle_brackets(self):
++        # Minimal guard: disallow '<' or '>' to prevent breaking tag context
++        with self.assertRaises(ValueError):
++            unparse({"m><tag>content</tag": "unsafe"}, full_document=False)
++
++    def test_rejects_attribute_name_with_angle_brackets(self):
++        # Now we expect bad attribute names to be rejected
++        with self.assertRaises(ValueError):
++            unparse(
++                {"a": {"@m><tag>content</tag": "unsafe", "#text": "x"}},
++                full_document=False,
++            )
++
++    def test_rejects_malicious_xmlns_prefix(self):
++        # xmlns prefixes go under @xmlns mapping; reject angle brackets in 
prefix
++        with self.assertRaises(ValueError):
++            unparse(
++                {
++                    "a": {
++                        "@xmlns": {"m><bad": "http://example.com/"},
++                        "#text": "x",
++                    }
++                },
++                full_document=False,
++            )
++
++    def test_attribute_values_with_angle_brackets_are_escaped(self):
++        # Attribute values should be escaped by XMLGenerator
++        xml = unparse({"a": {"@attr": "1<middle>2", "#text": "x"}}, 
full_document=False)
++        # The generated XML should contain escaped '<' and '>' within the 
attribute value
++        self.assertIn('attr="1&lt;middle&gt;2"', xml)
+diff --git a/xmltodict.py b/xmltodict.py
+index ca760aa..3de1c37 100755
+--- a/xmltodict.py
++++ b/xmltodict.py
+@@ -379,6 +379,14 @@ def parse(xml_input, encoding=None, expat=expat, 
process_namespaces=False,
+     return handler.item
+ 
+ 
++def _has_angle_brackets(value):
++    """Return True if value (a str) contains '<' or '>'.
++
++    Non-string values return False. Uses fast substring checks implemented in 
C.
++    """
++    return isinstance(value, str) and ("<" in value or ">" in value)
++
++
+ def _process_namespace(name, namespaces, ns_sep=':', attr_prefix='@'):
+     if not namespaces:
+         return name
+@@ -412,6 +420,9 @@ def _emit(key, value, content_handler,
+         if result is None:
+             return
+         key, value = result
++    # Minimal validation to avoid breaking out of tag context
++    if _has_angle_brackets(key):
++        raise ValueError('Invalid element name: "<" or ">" not allowed')
+     if (not hasattr(value, '__iter__')
+             or isinstance(value, _basestring)
+             or isinstance(value, dict)):
+@@ -445,12 +456,19 @@ def _emit(key, value, content_handler,
+                                         attr_prefix)
+                 if ik == '@xmlns' and isinstance(iv, dict):
+                     for k, v in iv.items():
++                        if _has_angle_brackets(k):
++                            raise ValueError(
++                                'Invalid attribute name: "<" or ">" not 
allowed'
++                            )
+                         attr = 'xmlns{}'.format(':{}'.format(k) if k else '')
+                         attrs[attr] = _unicode(v)
+                     continue
+                 if not isinstance(iv, _unicode):
+                     iv = _unicode(iv)
+-                attrs[ik[len(attr_prefix):]] = iv
++                attr_name = ik[len(attr_prefix) :]
++                if _has_angle_brackets(attr_name):
++                    raise ValueError('Invalid attribute name: "<" or ">" not 
allowed')
++                attrs[attr_name] = iv
+                 continue
+             children.append((ik, iv))
+         if pretty:
+-- 
+2.47.3
+
diff -Nru 
python-xmltodict-0.13.0/debian/patches/0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch
 
python-xmltodict-0.13.0/debian/patches/0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch
--- 
python-xmltodict-0.13.0/debian/patches/0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch
      1970-01-01 02:00:00.000000000 +0200
+++ 
python-xmltodict-0.13.0/debian/patches/0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch
      2026-06-28 20:17:51.000000000 +0300
@@ -0,0 +1,170 @@
+From 9f88d92c5cef9c3723fd502ac4e0c78a8f52d2f5 Mon Sep 17 00:00:00 2001
+From: Martin Blech <[email protected]>
+Date: Mon, 8 Sep 2025 11:18:33 -0700
+Subject: Enhance unparse() XML name validation with stricter rules and tests
+
+Extend existing validation (previously only for "<" and ">") to also
+reject element, attribute, and xmlns prefix names that are non-string,
+start with "?" or "!", or contain "/", spaces, tabs, or newlines.
+Update _emit and namespace handling to use _validate_name. Add tests
+covering these new invalid name cases.
+---
+ tests/test_dicttoxml.py | 60 +++++++++++++++++++++++++++++++++++++++++
+ xmltodict.py            | 48 ++++++++++++++++++++++++++-------
+ 2 files changed, 99 insertions(+), 9 deletions(-)
+
+diff --git a/tests/test_dicttoxml.py b/tests/test_dicttoxml.py
+index c0549e8..2e74949 100644
+--- a/tests/test_dicttoxml.py
++++ b/tests/test_dicttoxml.py
+@@ -245,3 +245,63 @@ xmlns:b="http://b.com/";><x 
a:attr="val">1</x><a:y>2</a:y><b:z>3</b:z></root>'''
+         xml = unparse({"a": {"@attr": "1<middle>2", "#text": "x"}}, 
full_document=False)
+         # The generated XML should contain escaped '<' and '>' within the 
attribute value
+         self.assertIn('attr="1&lt;middle&gt;2"', xml)
++
++    def test_rejects_tag_name_starting_with_question(self):
++        with self.assertRaises(ValueError):
++            unparse({"?pi": "data"}, full_document=False)
++
++    def test_rejects_tag_name_starting_with_bang(self):
++        with self.assertRaises(ValueError):
++            unparse({"!decl": "data"}, full_document=False)
++
++    def test_rejects_attribute_name_starting_with_question(self):
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@?weird": "x"}}, full_document=False)
++
++    def test_rejects_attribute_name_starting_with_bang(self):
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@!weird": "x"}}, full_document=False)
++
++    def test_rejects_xmlns_prefix_starting_with_question_or_bang(self):
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@xmlns": {"?p": "http://e/"}}}, 
full_document=False)
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@xmlns": {"!p": "http://e/"}}}, 
full_document=False)
++
++    def test_rejects_non_string_names(self):
++        class Weird:
++            def __str__(self):
++                return "bad>name"
++
++        # Non-string element key
++        with self.assertRaises(ValueError):
++            unparse({Weird(): "x"}, full_document=False)
++        # Non-string attribute key
++        with self.assertRaises(ValueError):
++            unparse({"a": {Weird(): "x"}}, full_document=False)
++
++    def test_rejects_tag_name_with_slash(self):
++        with self.assertRaises(ValueError):
++            unparse({"bad/name": "x"}, full_document=False)
++
++    def test_rejects_tag_name_with_whitespace(self):
++        for name in ["bad name", "bad\tname", "bad\nname"]:
++            with self.assertRaises(ValueError):
++                unparse({name: "x"}, full_document=False)
++
++    def test_rejects_attribute_name_with_slash(self):
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@bad/name": "x"}}, full_document=False)
++
++    def test_rejects_attribute_name_with_whitespace(self):
++        for name in ["@bad name", "@bad\tname", "@bad\nname"]:
++            with self.assertRaises(ValueError):
++                unparse({"a": {name: "x"}}, full_document=False)
++
++    def test_rejects_xmlns_prefix_with_slash_or_whitespace(self):
++        # Slash
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@xmlns": {"bad/prefix": "http://e/"}}}, 
full_document=False)
++        # Whitespace
++        with self.assertRaises(ValueError):
++            unparse({"a": {"@xmlns": {"bad prefix": "http://e/"}}}, 
full_document=False)
+diff --git a/xmltodict.py b/xmltodict.py
+index 3de1c37..3531169 100755
+--- a/xmltodict.py
++++ b/xmltodict.py
+@@ -387,7 +387,42 @@ def _has_angle_brackets(value):
+     return isinstance(value, str) and ("<" in value or ">" in value)
+ 
+ 
++def _has_invalid_name_chars(value):
++    """Return True if value (a str) contains any disallowed name characters.
++
++    Disallowed: '<', '>', '/', or any whitespace character.
++    Non-string values return False.
++    """
++    if not isinstance(value, str):
++        return False
++    if "<" in value or ">" in value or "/" in value:
++        return True
++    # Check for any whitespace (spaces, tabs, newlines, etc.)
++    return any(ch.isspace() for ch in value)
++
++
++def _validate_name(value, kind):
++    """Validate an element/attribute name for XML safety.
++
++    Raises ValueError with a specific reason when invalid.
++
++    kind: 'element' or 'attribute' (used in error messages)
++    """
++    if not isinstance(value, str):
++        raise ValueError(f"{kind} name must be a string")
++    if value.startswith("?") or value.startswith("!"):
++        raise ValueError(f'Invalid {kind} name: cannot start with "?" or "!"')
++    if "<" in value or ">" in value:
++        raise ValueError(f'Invalid {kind} name: "<" or ">" not allowed')
++    if "/" in value:
++        raise ValueError(f'Invalid {kind} name: "/" not allowed')
++    if any(ch.isspace() for ch in value):
++        raise ValueError(f"Invalid {kind} name: whitespace not allowed")
++
++
+ def _process_namespace(name, namespaces, ns_sep=':', attr_prefix='@'):
++    if not isinstance(name, str):
++        return name
+     if not namespaces:
+         return name
+     try:
+@@ -421,8 +456,7 @@ def _emit(key, value, content_handler,
+             return
+         key, value = result
+     # Minimal validation to avoid breaking out of tag context
+-    if _has_angle_brackets(key):
+-        raise ValueError('Invalid element name: "<" or ">" not allowed')
++    _validate_name(key, "element")
+     if (not hasattr(value, '__iter__')
+             or isinstance(value, _basestring)
+             or isinstance(value, dict)):
+@@ -451,23 +485,19 @@ def _emit(key, value, content_handler,
+             if ik == cdata_key:
+                 cdata = iv
+                 continue
+-            if ik.startswith(attr_prefix):
++            if isinstance(ik, str) and ik.startswith(attr_prefix):
+                 ik = _process_namespace(ik, namespaces, namespace_separator,
+                                         attr_prefix)
+                 if ik == '@xmlns' and isinstance(iv, dict):
+                     for k, v in iv.items():
+-                        if _has_angle_brackets(k):
+-                            raise ValueError(
+-                                'Invalid attribute name: "<" or ">" not 
allowed'
+-                            )
++                        _validate_name(k, "attribute")
+                         attr = 'xmlns{}'.format(':{}'.format(k) if k else '')
+                         attrs[attr] = _unicode(v)
+                     continue
+                 if not isinstance(iv, _unicode):
+                     iv = _unicode(iv)
+                 attr_name = ik[len(attr_prefix) :]
+-                if _has_angle_brackets(attr_name):
+-                    raise ValueError('Invalid attribute name: "<" or ">" not 
allowed')
++                _validate_name(attr_name, "attribute")
+                 attrs[attr_name] = iv
+                 continue
+             children.append((ik, iv))
+-- 
+2.47.3
+
diff -Nru 
python-xmltodict-0.13.0/debian/patches/0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch
 
python-xmltodict-0.13.0/debian/patches/0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch
--- 
python-xmltodict-0.13.0/debian/patches/0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch
      1970-01-01 02:00:00.000000000 +0200
+++ 
python-xmltodict-0.13.0/debian/patches/0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch
      2026-06-28 20:17:51.000000000 +0300
@@ -0,0 +1,50 @@
+From 02d78e3bf009b479b9d20415cf4c81a5225dc6a0 Mon Sep 17 00:00:00 2001
+From: Martin Blech <[email protected]>
+Date: Mon, 8 Sep 2025 11:28:38 -0700
+Subject: Harden XML name validation: reject quotes and '='; add tests
+
+---
+ tests/test_dicttoxml.py | 14 ++++++++++++++
+ xmltodict.py            |  4 ++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/tests/test_dicttoxml.py b/tests/test_dicttoxml.py
+index 2e74949..9830e2a 100644
+--- a/tests/test_dicttoxml.py
++++ b/tests/test_dicttoxml.py
+@@ -305,3 +305,17 @@ xmlns:b="http://b.com/";><x 
a:attr="val">1</x><a:y>2</a:y><b:z>3</b:z></root>'''
+         # Whitespace
+         with self.assertRaises(ValueError):
+             unparse({"a": {"@xmlns": {"bad prefix": "http://e/"}}}, 
full_document=False)
++
++    def test_rejects_names_with_quotes_and_equals(self):
++        # Element names
++        for name in ['a"b', "a'b", "a=b"]:
++            with self.assertRaises(ValueError):
++                unparse({name: "x"}, full_document=False)
++        # Attribute names
++        for name in ['@a"b', "@a'b", "@a=b"]:
++            with self.assertRaises(ValueError):
++                unparse({"a": {name: "x"}}, full_document=False)
++        # xmlns prefixes
++        for prefix in ['a"b', "a'b", "a=b"]:
++            with self.assertRaises(ValueError):
++                unparse({"a": {"@xmlns": {prefix: "http://e/"}}}, 
full_document=False)
+diff --git a/xmltodict.py b/xmltodict.py
+index 3531169..788017f 100755
+--- a/xmltodict.py
++++ b/xmltodict.py
+@@ -416,6 +416,10 @@ def _validate_name(value, kind):
+         raise ValueError(f'Invalid {kind} name: "<" or ">" not allowed')
+     if "/" in value:
+         raise ValueError(f'Invalid {kind} name: "/" not allowed')
++    if '"' in value or "'" in value:
++        raise ValueError(f"Invalid {kind} name: quotes not allowed")
++    if "=" in value:
++        raise ValueError(f'Invalid {kind} name: "=" not allowed')
+     if any(ch.isspace() for ch in value):
+         raise ValueError(f"Invalid {kind} name: whitespace not allowed")
+ 
+-- 
+2.47.3
+
diff -Nru python-xmltodict-0.13.0/debian/patches/series 
python-xmltodict-0.13.0/debian/patches/series
--- python-xmltodict-0.13.0/debian/patches/series       1970-01-01 
02:00:00.000000000 +0200
+++ python-xmltodict-0.13.0/debian/patches/series       2026-06-28 
20:26:01.000000000 +0300
@@ -0,0 +1,3 @@
+0001-Prevent-XML-injection-reject-in-element-attr-names-i.patch
+0002-Enhance-unparse-XML-name-validation-with-stricter-ru.patch
+0003-Harden-XML-name-validation-reject-quotes-and-add-tes.patch

--- End Message ---
--- Begin Message ---
Version: 13.6

This update was released as part of 13.6.

--- End Message ---

Reply via email to