Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-xmltodict for 
openSUSE:Factory checked in at 2025-09-10 17:30:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-xmltodict (Old)
 and      /work/SRC/openSUSE:Factory/.python-xmltodict.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-xmltodict"

Wed Sep 10 17:30:07 2025 rev:11 rq:1303377 version:0.15.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-xmltodict/python-xmltodict.changes        
2024-10-30 17:32:53.432372473 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-xmltodict.new.1977/python-xmltodict.changes  
    2025-09-10 17:30:10.141349759 +0200
@@ -1,0 +2,21 @@
+Tue Sep  9 07:46:33 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 0.15.1
+  * Security: Further harden XML injection prevention during unparse (follow-up
+    to v0.15.0). In addition to '<'/'>' rejection, now also reject element and
+    attribute names (including `@xmlns` prefixes) that:
+    - start with '?' or '!'
+    - contain '/' or any whitespace
+    - contain quotes (' or ") or '='
+    - are non-strings (names must be `str`; no coercion)
+
+-------------------------------------------------------------------
+Mon Sep  8 11:26:39 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 0.15.0
+  * Security: Prevent XML injection (CVE-2025-9375) by rejecting '<'/'>' in
+    element and attribute names (including `@xmlns` prefixes) during unparse.
+    This limits validation to avoiding tag-context escapes; attribute values
+    continue to be escaped by the SAX `XMLGenerator`. (bsc#1249036, 
CVE-2025-9375)
+
+-------------------------------------------------------------------

Old:
----
  xmltodict-0.14.2.tar.gz

New:
----
  xmltodict-0.15.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-xmltodict.spec ++++++
--- /var/tmp/diff_new_pack.IIMlv8/_old  2025-09-10 17:30:11.013386428 +0200
+++ /var/tmp/diff_new_pack.IIMlv8/_new  2025-09-10 17:30:11.013386428 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-xmltodict
-Version:        0.14.2
+Version:        0.15.1
 Release:        0
 Summary:        Module to make XML working resemble JSON
 License:        MIT

++++++ xmltodict-0.14.2.tar.gz -> xmltodict-0.15.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/PKG-INFO 
new/xmltodict-0.15.1/PKG-INFO
--- old/xmltodict-0.14.2/PKG-INFO       2024-10-16 08:10:02.723137400 +0200
+++ new/xmltodict-0.15.1/PKG-INFO       2025-09-08 20:33:12.287541400 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: xmltodict
-Version: 0.14.2
+Version: 0.15.1
 Summary: Makes working with XML feel like you are working with JSON
 Home-page: https://github.com/martinblech/xmltodict
 Author: Martin Blech
@@ -12,9 +12,6 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
@@ -22,9 +19,20 @@
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Text Processing :: Markup :: XML
-Requires-Python: >=3.6
+Requires-Python: >=3.9
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: platform
+Dynamic: requires-python
+Dynamic: summary
 
 # xmltodict
 
@@ -46,15 +54,15 @@
 ...  """), indent=4))
 {
     "mydocument": {
-        "@has": "an attribute", 
+        "@has": "an attribute",
         "and": {
             "many": [
-                "elements", 
+                "elements",
                 "more elements"
             ]
-        }, 
+        },
         "plus": {
-            "@a": "complex", 
+            "@a": "complex",
             "#text": "element as well"
         }
     }
@@ -110,7 +118,7 @@
 >>> def handle_artist(_, artist):
 ...     print(artist['name'])
 ...     return True
->>> 
+>>>
 >>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'),
 ...     item_depth=2, item_callback=handle_artist)
 A Perfect Circle
@@ -178,7 +186,7 @@
 
 ```python
 >>> import xmltodict
->>> 
+>>>
 >>> mydict = {
 ...     'text': {
 ...         '@color':'red',
@@ -234,7 +242,7 @@
 
 ### Using conda
 
-For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the 
+For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the
 [conda-forge channel][#xmltodict-conda] all you need to do is:
 
 [#xmltodict-conda]: https://anaconda.org/conda-forge/xmltodict
@@ -286,3 +294,13 @@
 # Python3
 $ zypper in python3-xmltodict
 ```
+
+## Security Notes
+
+A CVE (CVE-2025-9375) was filed against `xmltodict` but is 
[disputed](https://github.com/martinblech/xmltodict/issues/377#issuecomment-3255691923).
 The root issue lies in Python’s `xml.sax.saxutils.XMLGenerator` API, which 
does not validate XML element names and provides no built-in way to do so. 
Since `xmltodict` is a thin wrapper that passes keys directly to 
`XMLGenerator`, the same issue exists in the standard library itself.
+
+It has been suggested that `xml.sax.saxutils.escape()` represents a secure 
usage path. This is incorrect: `escape()` is intended only for character data 
and attribute values, and can produce invalid XML when misapplied to element 
names. There is currently no secure, documented way in Python’s standard 
library to validate XML element names.
+
+Despite this, Fluid Attacks chose to assign a CVE to `xmltodict` while leaving 
the identical behavior in Python’s own standard library unaddressed. Their 
disclosure process also gave only 10 days from first contact to 
publication—well short of the 90-day industry norm—leaving no real opportunity 
for maintainer response. These actions reflect an inconsistency of standards 
and priorities that raise concerns about motivations, as they do not primarily 
serve the security of the broader community.
+
+The maintainer considers this CVE invalid and will formally dispute it with 
MITRE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/README.md 
new/xmltodict-0.15.1/README.md
--- old/xmltodict-0.14.2/README.md      2024-10-08 19:41:22.000000000 +0200
+++ new/xmltodict-0.15.1/README.md      2025-09-04 23:33:22.000000000 +0200
@@ -18,15 +18,15 @@
 ...  """), indent=4))
 {
     "mydocument": {
-        "@has": "an attribute", 
+        "@has": "an attribute",
         "and": {
             "many": [
-                "elements", 
+                "elements",
                 "more elements"
             ]
-        }, 
+        },
         "plus": {
-            "@a": "complex", 
+            "@a": "complex",
             "#text": "element as well"
         }
     }
@@ -82,7 +82,7 @@
 >>> def handle_artist(_, artist):
 ...     print(artist['name'])
 ...     return True
->>> 
+>>>
 >>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'),
 ...     item_depth=2, item_callback=handle_artist)
 A Perfect Circle
@@ -150,7 +150,7 @@
 
 ```python
 >>> import xmltodict
->>> 
+>>>
 >>> mydict = {
 ...     'text': {
 ...         '@color':'red',
@@ -206,7 +206,7 @@
 
 ### Using conda
 
-For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the 
+For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the
 [conda-forge channel][#xmltodict-conda] all you need to do is:
 
 [#xmltodict-conda]: https://anaconda.org/conda-forge/xmltodict
@@ -258,3 +258,13 @@
 # Python3
 $ zypper in python3-xmltodict
 ```
+
+## Security Notes
+
+A CVE (CVE-2025-9375) was filed against `xmltodict` but is 
[disputed](https://github.com/martinblech/xmltodict/issues/377#issuecomment-3255691923).
 The root issue lies in Python’s `xml.sax.saxutils.XMLGenerator` API, which 
does not validate XML element names and provides no built-in way to do so. 
Since `xmltodict` is a thin wrapper that passes keys directly to 
`XMLGenerator`, the same issue exists in the standard library itself.
+
+It has been suggested that `xml.sax.saxutils.escape()` represents a secure 
usage path. This is incorrect: `escape()` is intended only for character data 
and attribute values, and can produce invalid XML when misapplied to element 
names. There is currently no secure, documented way in Python’s standard 
library to validate XML element names.
+
+Despite this, Fluid Attacks chose to assign a CVE to `xmltodict` while leaving 
the identical behavior in Python’s own standard library unaddressed. Their 
disclosure process also gave only 10 days from first contact to 
publication—well short of the 90-day industry norm—leaving no real opportunity 
for maintainer response. These actions reflect an inconsistency of standards 
and priorities that raise concerns about motivations, as they do not primarily 
serve the security of the broader community.
+
+The maintainer considers this CVE invalid and will formally dispute it with 
MITRE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/setup.py 
new/xmltodict-0.15.1/setup.py
--- old/xmltodict-0.14.2/setup.py       2024-10-09 21:19:57.000000000 +0200
+++ new/xmltodict-0.15.1/setup.py       2025-09-05 03:23:12.000000000 +0200
@@ -12,34 +12,32 @@
     long_description = f.read().decode('utf-8')
 
 
-setup(name='xmltodict',
-      version=xmltodict.__version__,
-      description=xmltodict.__doc__,
-      long_description=long_description,
-      long_description_content_type='text/markdown',
-      author=xmltodict.__author__,
-      author_email='[email protected]',
-      url='https://github.com/martinblech/xmltodict',
-      license=xmltodict.__license__,
-      platforms=['all'],
-      python_requires='>=3.6',
-      classifiers=[
-          'Intended Audience :: Developers',
-          'License :: OSI Approved :: MIT License',
-          'Operating System :: OS Independent',
-          'Programming Language :: Python',
-          'Programming Language :: Python :: 3',
-          'Programming Language :: Python :: 3.6',
-          'Programming Language :: Python :: 3.7',
-          'Programming Language :: Python :: 3.8',
-          'Programming Language :: Python :: 3.9',
-          'Programming Language :: Python :: 3.10',
-          'Programming Language :: Python :: 3.11',
-          'Programming Language :: Python :: 3.12',
-          'Programming Language :: Python :: 3.13',
-          'Programming Language :: Python :: Implementation :: PyPy',
-          'Topic :: Text Processing :: Markup :: XML',
-      ],
-      py_modules=['xmltodict'],
-      tests_require=['nose2', 'coverage'],
-      )
+setup(
+    name="xmltodict",
+    version=xmltodict.__version__,
+    description=xmltodict.__doc__,
+    long_description=long_description,
+    long_description_content_type="text/markdown",
+    author=xmltodict.__author__,
+    author_email="[email protected]",
+    url="https://github.com/martinblech/xmltodict";,
+    license=xmltodict.__license__,
+    platforms=["all"],
+    python_requires=">=3.9",
+    classifiers=[
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: MIT License",
+        "Operating System :: OS Independent",
+        "Programming Language :: Python",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
+        "Programming Language :: Python :: 3.12",
+        "Programming Language :: Python :: 3.13",
+        "Programming Language :: Python :: Implementation :: PyPy",
+        "Topic :: Text Processing :: Markup :: XML",
+    ],
+    py_modules=["xmltodict"],
+    tests_require=["nose2", "coverage"],
+)
Binary files old/xmltodict-0.14.2/tests/__pycache__/__init__.cpython-313.pyc 
and new/xmltodict-0.15.1/tests/__pycache__/__init__.cpython-313.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_dicttoxml.cpython-311.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_dicttoxml.cpython-311.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_dicttoxml.cpython-312.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_dicttoxml.cpython-312.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_dicttoxml.cpython-313.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_dicttoxml.cpython-313.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_xmltodict.cpython-311.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_xmltodict.cpython-311.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_xmltodict.cpython-312.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_xmltodict.cpython-312.pyc differ
Binary files 
old/xmltodict-0.14.2/tests/__pycache__/test_xmltodict.cpython-313.pyc and 
new/xmltodict-0.15.1/tests/__pycache__/test_xmltodict.cpython-313.pyc differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/tests/test_dicttoxml.py 
new/xmltodict-0.15.1/tests/test_dicttoxml.py
--- old/xmltodict-0.14.2/tests/test_dicttoxml.py        2024-10-08 
20:03:35.000000000 +0200
+++ new/xmltodict-0.15.1/tests/test_dicttoxml.py        2025-09-08 
20:28:39.000000000 +0200
@@ -231,3 +231,109 @@
         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)
+
+    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)
+
+    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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/xmltodict.egg-info/PKG-INFO 
new/xmltodict-0.15.1/xmltodict.egg-info/PKG-INFO
--- old/xmltodict-0.14.2/xmltodict.egg-info/PKG-INFO    2024-10-16 
08:10:02.000000000 +0200
+++ new/xmltodict-0.15.1/xmltodict.egg-info/PKG-INFO    2025-09-08 
20:33:12.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: xmltodict
-Version: 0.14.2
+Version: 0.15.1
 Summary: Makes working with XML feel like you are working with JSON
 Home-page: https://github.com/martinblech/xmltodict
 Author: Martin Blech
@@ -12,9 +12,6 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
@@ -22,9 +19,20 @@
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Text Processing :: Markup :: XML
-Requires-Python: >=3.6
+Requires-Python: >=3.9
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: platform
+Dynamic: requires-python
+Dynamic: summary
 
 # xmltodict
 
@@ -46,15 +54,15 @@
 ...  """), indent=4))
 {
     "mydocument": {
-        "@has": "an attribute", 
+        "@has": "an attribute",
         "and": {
             "many": [
-                "elements", 
+                "elements",
                 "more elements"
             ]
-        }, 
+        },
         "plus": {
-            "@a": "complex", 
+            "@a": "complex",
             "#text": "element as well"
         }
     }
@@ -110,7 +118,7 @@
 >>> def handle_artist(_, artist):
 ...     print(artist['name'])
 ...     return True
->>> 
+>>>
 >>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'),
 ...     item_depth=2, item_callback=handle_artist)
 A Perfect Circle
@@ -178,7 +186,7 @@
 
 ```python
 >>> import xmltodict
->>> 
+>>>
 >>> mydict = {
 ...     'text': {
 ...         '@color':'red',
@@ -234,7 +242,7 @@
 
 ### Using conda
 
-For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the 
+For installing `xmltodict` using Anaconda/Miniconda (*conda*) from the
 [conda-forge channel][#xmltodict-conda] all you need to do is:
 
 [#xmltodict-conda]: https://anaconda.org/conda-forge/xmltodict
@@ -286,3 +294,13 @@
 # Python3
 $ zypper in python3-xmltodict
 ```
+
+## Security Notes
+
+A CVE (CVE-2025-9375) was filed against `xmltodict` but is 
[disputed](https://github.com/martinblech/xmltodict/issues/377#issuecomment-3255691923).
 The root issue lies in Python’s `xml.sax.saxutils.XMLGenerator` API, which 
does not validate XML element names and provides no built-in way to do so. 
Since `xmltodict` is a thin wrapper that passes keys directly to 
`XMLGenerator`, the same issue exists in the standard library itself.
+
+It has been suggested that `xml.sax.saxutils.escape()` represents a secure 
usage path. This is incorrect: `escape()` is intended only for character data 
and attribute values, and can produce invalid XML when misapplied to element 
names. There is currently no secure, documented way in Python’s standard 
library to validate XML element names.
+
+Despite this, Fluid Attacks chose to assign a CVE to `xmltodict` while leaving 
the identical behavior in Python’s own standard library unaddressed. Their 
disclosure process also gave only 10 days from first contact to 
publication—well short of the 90-day industry norm—leaving no real opportunity 
for maintainer response. These actions reflect an inconsistency of standards 
and priorities that raise concerns about motivations, as they do not primarily 
serve the security of the broader community.
+
+The maintainer considers this CVE invalid and will formally dispute it with 
MITRE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/xmltodict.egg-info/SOURCES.txt 
new/xmltodict-0.15.1/xmltodict.egg-info/SOURCES.txt
--- old/xmltodict-0.14.2/xmltodict.egg-info/SOURCES.txt 2024-10-16 
08:10:02.000000000 +0200
+++ new/xmltodict-0.15.1/xmltodict.egg-info/SOURCES.txt 2025-09-08 
20:33:12.000000000 +0200
@@ -10,14 +10,17 @@
 tests/test_xmltodict.py
 tests/__pycache__/__init__.cpython-311.pyc
 tests/__pycache__/__init__.cpython-312.pyc
+tests/__pycache__/__init__.cpython-313.pyc
 tests/__pycache__/test_dicttoxml.cpython-310.pyc
 tests/__pycache__/test_dicttoxml.cpython-311.pyc
 tests/__pycache__/test_dicttoxml.cpython-312.pyc
+tests/__pycache__/test_dicttoxml.cpython-313.pyc
 tests/__pycache__/test_dicttoxml.cpython-37.pyc
 tests/__pycache__/test_dicttoxml.cpython-39.pyc
 tests/__pycache__/test_xmltodict.cpython-310.pyc
 tests/__pycache__/test_xmltodict.cpython-311.pyc
 tests/__pycache__/test_xmltodict.cpython-312.pyc
+tests/__pycache__/test_xmltodict.cpython-313.pyc
 tests/__pycache__/test_xmltodict.cpython-37.pyc
 tests/__pycache__/test_xmltodict.cpython-39.pyc
 xmltodict.egg-info/PKG-INFO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmltodict-0.14.2/xmltodict.py 
new/xmltodict-0.15.1/xmltodict.py
--- old/xmltodict-0.14.2/xmltodict.py   2024-10-16 08:06:57.000000000 +0200
+++ new/xmltodict-0.15.1/xmltodict.py   2025-09-08 20:29:07.000000000 +0200
@@ -14,7 +14,7 @@
 from inspect import isgenerator
 
 __author__ = 'Martin Blech'
-__version__ = "0.14.2"
+__version__ = "0.15.1"
 __license__ = 'MIT'
 
 
@@ -360,7 +360,54 @@
     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 _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 '"' 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")
+
+
 def _process_namespace(name, namespaces, ns_sep=':', attr_prefix='@'):
+    if not isinstance(name, str):
+        return name
     if not namespaces:
         return name
     try:
@@ -393,6 +440,8 @@
         if result is None:
             return
         key, value = result
+    # Minimal validation to avoid breaking out of tag context
+    _validate_name(key, "element")
     if not hasattr(value, '__iter__') or isinstance(value, (str, dict)):
         value = [value]
     for index, v in enumerate(value):
@@ -416,17 +465,20 @@
             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():
+                        _validate_name(k, "attribute")
                         attr = 'xmlns{}'.format(f':{k}' if k else '')
                         attrs[attr] = str(v)
                     continue
                 if not isinstance(iv, str):
                     iv = str(iv)
-                attrs[ik[len(attr_prefix):]] = iv
+                attr_name = ik[len(attr_prefix) :]
+                _validate_name(attr_name, "attribute")
+                attrs[attr_name] = iv
                 continue
             children.append((ik, iv))
         if isinstance(indent, int):

Reply via email to