Bug report
Bug description:
Summary
dumps() interpolates the method name directly into <methodName> tags without XML escaping. If an application derives methodname from user input, an attacker can inject XML markup into the request body.
Details
The method name is interpolated into a tuple that is later joined into the final XML string:
| if methodname: | |
| # a method call | |
| data = ( | |
| xmlheader, | |
| "<methodCall>\n" | |
| "<methodName>", methodname, "</methodName>\n", | |
| data, | |
| "</methodCall>\n" | |
| ) |
The tuple is serialized via "".join(data). The method name is written raw into XML without calling the module's escape() helper (used elsewhere, e.g., for string values in dump_unicode).
Reproducer
import xml.etree.ElementTree as ET from xmlrpc.client import dumps def main(): payload = 'foo</methodName><injected attr="evil"/><methodName>bar' result = dumps((), methodname=payload) root = ET.fromstring(result) method_names = root.findall("methodName") assert len(method_names) == 2, ( f"Expected 2 <methodName> elements from injection, got " f"{len(method_names)}" ) print("Generated XML:") print(result) if __name__ == "__main__": main()
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS
Linked PRs
- gh-148954: Escape methodname in xmlrpc.client.dumps() to prevent XML injection #148968
- [3.15] gh-148954: Escape methodname in xmlrpc.client.dumps() to prevent XML injection (GH-148968) #151033
- [3.14] gh-148954: Escape methodname in xmlrpc.client.dumps() to prevent XML injection (GH-148968) #151034
- [3.13] gh-148954: Escape methodname in xmlrpc.client.dumps() to prevent XML injection (GH-148968) #151035