From 4e67dfdcae93edc09e3124fabdfd104888ff7522 Mon Sep 17 00:00:00 2001 From: sanyamk23 Date: Fri, 24 Apr 2026 22:55:09 +0530 Subject: [PATCH 1/5] gh-148954: sanitize methodname in xmlrpc.client.dumps() to prevent XML injection --- Lib/xmlrpc/client.py | 2 +- .../next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index f441376d09c4aa..84e4e4d11a7319 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -965,7 +965,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None, data = ( xmlheader, "\n" - "", methodname, "\n", + "", escape(methodname), "\n", data, "\n" ) diff --git a/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst b/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst new file mode 100644 index 00000000000000..3eabcfdafe6875 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst @@ -0,0 +1,2 @@ +Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the ``methodname`` +was not being escaped before interpolation into the XML body. From 6e1f96d3ab22e77604f3af0eeeec0ad77b733416 Mon Sep 17 00:00:00 2001 From: sanyamk23 Date: Fri, 24 Apr 2026 22:58:57 +0530 Subject: [PATCH 2/5] gh-148954: add tests for methodname sanitization in dumps() --- Lib/test/test_xmlrpc.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 2803c6d45c27bf..ab4f1cea6ec251 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -208,6 +208,15 @@ def test_dump_encoding(self): self.assertEqual(xmlrpclib.loads(strg)[0][0], value) self.assertEqual(xmlrpclib.loads(strg)[1], methodname) + def test_methodname_sanitization(self): + # gh-148954: test that methodname is sanitized in dumps() + payload = 'foobar' + s = xmlrpclib.dumps((), methodname=payload) + self.assertIn('foo</methodName><injected attr="evil"/><methodName>bar', s) + self.assertNotIn('', s) + load, m = xmlrpclib.loads(s) + self.assertEqual(m, payload) + def test_dump_bytes(self): sample = b"my dog has fleas" self.assertEqual(sample, xmlrpclib.Binary(sample)) From 115b915ec291dbb1832b1c584b69de69e337ad39 Mon Sep 17 00:00:00 2001 From: sanyamk23 Date: Fri, 24 Apr 2026 23:02:08 +0530 Subject: [PATCH 3/5] gh-148954: rename test and wrap long line --- Lib/test/test_xmlrpc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index ab4f1cea6ec251..a3dc8c74b5f572 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -208,11 +208,14 @@ def test_dump_encoding(self): self.assertEqual(xmlrpclib.loads(strg)[0][0], value) self.assertEqual(xmlrpclib.loads(strg)[1], methodname) - def test_methodname_sanitization(self): + def test_dump_escape_methodname(self): # gh-148954: test that methodname is sanitized in dumps() payload = 'foobar' s = xmlrpclib.dumps((), methodname=payload) - self.assertIn('foo</methodName><injected attr="evil"/><methodName>bar', s) + self.assertIn( + 'foo</methodName><injected attr="evil"/>' + '<methodName>bar', s + ) self.assertNotIn('', s) load, m = xmlrpclib.loads(s) self.assertEqual(m, payload) From 4392570d3f2499324de18f7b2c7b3f6c19d6d21b Mon Sep 17 00:00:00 2001 From: sanyamk23 Date: Fri, 24 Apr 2026 23:03:33 +0530 Subject: [PATCH 4/5] gh-148954: remove test comments --- Lib/test/test_xmlrpc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index a3dc8c74b5f572..ee0e24f6e86ae3 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -209,7 +209,6 @@ def test_dump_encoding(self): self.assertEqual(xmlrpclib.loads(strg)[1], methodname) def test_dump_escape_methodname(self): - # gh-148954: test that methodname is sanitized in dumps() payload = 'foobar' s = xmlrpclib.dumps((), methodname=payload) self.assertIn( From bbf4bdf376b8592b2d6e3c10ee0c5fe1423b04f7 Mon Sep 17 00:00:00 2001 From: sanyamk23 Date: Fri, 24 Apr 2026 23:12:46 +0530 Subject: [PATCH 5/5] gh-148954: move NEWS entry to Library --- .../next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst | 1 + .../next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst delete mode 100644 Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst diff --git a/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst b/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst new file mode 100644 index 00000000000000..6245af7e362e92 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-24-19-54-00.gh-issue-148954.v1.rst @@ -0,0 +1 @@ +Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the ``methodname`` was not being escaped before interpolation into the XML body. diff --git a/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst b/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst deleted file mode 100644 index 3eabcfdafe6875..00000000000000 --- a/Misc/NEWS.d/next/Security/2026-04-24-19-54-00.gh-issue-148954.v1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix XML injection vulnerability in :func:`xmlrpc.client.dumps` where the ``methodname`` -was not being escaped before interpolation into the XML body.