# PYTHON-LANG-SEC-092: Insecure xmlrpc Usage (XXE Risk)

> **Severity:** MEDIUM | **CWE:** CWE-611 | **OWASP:** A05:2021

- **Language:** Python
- **Category:** Python Core
- **URL:** https://codepathfinder.dev/registry/python/lang/PYTHON-LANG-SEC-092
- **Detection:** `pathfinder scan --ruleset python/PYTHON-LANG-SEC-092 --project .`

## Description

Python's xmlrpc module implements the XML-RPC protocol for remote procedure calls.
XML-RPC uses XML as its encoding format, and the parser used by xmlrpc.server and
xmlrpc.client is vulnerable to XXE attacks when processing malicious XML-RPC payloads.

An attacker who can send XML-RPC requests to a server can craft payloads with external
entity references that read local files or make network requests. On the client side,
a malicious XML-RPC server can send responses with XXE payloads that read files on
the client system.

defusedxml.xmlrpc monkey-patches the xmlrpc module to use safe XML parsing, preventing
XXE attacks. For new implementations, REST over HTTPS is a more secure alternative
to XML-RPC.


## Vulnerable Code

```python
import xml.etree.ElementTree as ET
import xml.dom.minidom
import xml.sax
import xmlrpc.client
import csv

# SEC-092: xmlrpc
proxy = xmlrpc.client.ServerProxy("http://example.com/rpc")
```

## Secure Code

```python
# INSECURE: xmlrpc without XXE protection
# import xmlrpc.client
# proxy = xmlrpc.client.ServerProxy("http://api.example.com/xmlrpc")

# SECURE: Use defusedxml.xmlrpc to patch the xmlrpc module
import defusedxml.xmlrpc
defusedxml.xmlrpc.monkey_patch()  # Must be called before using xmlrpc

import xmlrpc.client

def call_xmlrpc_api(url: str, method: str, *args):
    """Call XML-RPC API with defusedxml protection applied."""
    proxy = xmlrpc.client.ServerProxy(url)
    return getattr(proxy, method)(*args)

# PREFERRED: Migrate to REST API using requests
import requests

def call_rest_api(base_url: str, endpoint: str, data: dict) -> dict:
    response = requests.post(
        f"{base_url}/{endpoint}",
        json=data,
        timeout=30,
    )
    response.raise_for_status()
    return response.json()

# SECURE: XML-RPC server with defusedxml patching
def create_safe_xmlrpc_server(host: str, port: int):
    import defusedxml.xmlrpc
    defusedxml.xmlrpc.monkey_patch()
    from xmlrpc.server import SimpleXMLRPCServer
    server = SimpleXMLRPCServer((host, port))
    return server

```

## Detection Rule (Python SDK)

```python
from rules.python_decorators import python_rule
from codepathfinder import calls, QueryType

class XMLRPCModule(QueryType):
    fqns = ["xmlrpc", "xmlrpc.client", "xmlrpc.server"]


@python_rule(
    id="PYTHON-LANG-SEC-092",
    name="Insecure xmlrpc Usage",
    severity="MEDIUM",
    category="lang",
    cwe="CWE-611",
    tags="python,xmlrpc,xxe,CWE-611",
    message="xmlrpc is vulnerable to XXE. Use defusedxml.xmlrpc instead.",
    owasp="A05:2021",
)
def detect_xmlrpc():
    """Detects xmlrpc.client and xmlrpc.server usage."""
    return XMLRPCModule.method("ServerProxy", "SimpleXMLRPCServer", "DocXMLRPCServer")
```

## How to Fix

- Call defusedxml.xmlrpc.monkey_patch() before using any xmlrpc module to patch the XML parser to prevent XXE.
- For new implementations, migrate from XML-RPC to REST over HTTPS for a more secure, modern, and widely supported API protocol.
- Use HTTPS instead of HTTP for all XML-RPC endpoints to protect credentials and data in transit.
- Implement authentication and authorization on XML-RPC endpoints; the protocol itself provides no access control.
- Validate and restrict XML-RPC method names and parameters to an explicit allowlist to prevent exploitation of server-side methods.

## Security Implications

- **Server-Side File Disclosure via XML-RPC XXE:** A client sending a malicious XML-RPC request with XXE entities can cause the server
to read local files (configuration files, credentials, SSH keys) and include their
contents in error responses or method parameters.

- **SSRF via XML-RPC Client:** When an XML-RPC client receives a malicious response from a compromised or malicious
server, XXE entities in the response can cause the client to make HTTP requests to
internal network resources or cloud metadata endpoints.

- **XML-RPC Server DoS via DTD:** Billion Laughs attacks via XML-RPC requests can exhaust server memory and CPU
resources, causing denial of service for legitimate users.

- **Blind XXE via XML-RPC Fault Responses:** XML-RPC fault responses can contain XXE payloads. Blind XXE via out-of-band DNS
or HTTP callbacks to attacker-controlled servers can exfiltrate data even when
fault content is not directly returned to the attacker.


## FAQ

**Q: What does defusedxml.xmlrpc.monkey_patch() do?**

monkey_patch() replaces the XML parser used internally by xmlrpc.client and
xmlrpc.server with defusedxml's safe parser. After calling monkey_patch(), all
XML-RPC parsing is done through defusedxml, blocking XXE, Billion Laughs, and
other XML attacks. Call it once at application startup before any xmlrpc imports.


**Q: Is XML-RPC still a reasonable protocol to use?**

XML-RPC is a legacy protocol designed in the late 1990s. Modern alternatives (REST
over HTTPS with JSON, gRPC, GraphQL) are more secure, performant, and widely
supported. If you must maintain XML-RPC for backward compatibility, apply defusedxml
patching and consider providing a REST alternative for new integrations.


**Q: Does this rule apply to XML-RPC over HTTPS?**

Yes. Using HTTPS for XML-RPC protects data in transit and authenticates the server,
but it does not prevent XXE in the XML payload itself. An attacker who has valid
access to the XML-RPC endpoint (or compromises the HTTPS connection) can still send
malicious XML-RPC payloads. defusedxml is needed regardless of transport security.


**Q: Are there CVEs for Python's xmlrpc XXE vulnerability?**

Yes. Multiple CVEs have been reported for XML-RPC implementations across various
programming languages and Python versions. The Python standard library's xmlrpc
module's XXE vulnerability is documented and the defusedxml library was created
specifically to address it along with other XML security issues in Python.


**Q: Is xmlrpc.client safe when only reading responses (not sending)?**

No. XXE can occur in both request parsing (server-side) and response parsing
(client-side). A malicious or compromised XML-RPC server can send responses with
XXE payloads that cause the client's parser to read local files. Apply defusedxml
patching for both client and server usage.


**Q: Can I use xmlrpc for internal microservice communication safely?**

Apply defusedxml.xmlrpc.monkey_patch() and use HTTPS with mutual TLS for internal
communication. Restrict access to the XML-RPC endpoint to authorized services via
network policies. However, REST over HTTPS with JSON is strongly preferred for new
microservice APIs due to better tooling, documentation, and security support.


## References

- [CWE-611: Improper Restriction of XML External Entity Reference](https://cwe.mitre.org/data/definitions/611.html)
- [Python docs: xmlrpc.client](https://docs.python.org/3/library/xmlrpc.client.html)
- [defusedxml.xmlrpc documentation](https://github.com/tiran/defusedxml#defusedxmlxmlrpc)
- [OWASP XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html)
- [OWASP Top 10 A05:2021 Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/)

---

Source: https://codepathfinder.dev/registry/python/lang/PYTHON-LANG-SEC-092
Code Pathfinder — Open source, type-aware SAST with cross-file dataflow analysis
