Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .chronus/changes/main-2025-8-17-12-23-40.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/http-client-python"
---

Explicitly use element tree parser with resolve_entities set to False
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import enum
import email.utils
from datetime import datetime, date, time, timedelta, timezone
from json import JSONEncoder
import lxml.etree as etree
import xml.etree.ElementTree as ET
from collections.abc import MutableMapping
from typing_extensions import Self
Expand All @@ -34,6 +35,9 @@ __all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"]
TZ_UTC = timezone.utc
_T = typing.TypeVar("_T")

_XML_PARSER = etree.XMLParser(resolve_entities=False)
"""Avoid XML entity resolution to prevent XXE attacks. (https://github.com/microsoft/typespec/issues/8083)"""


def _timedelta_as_isostr(td: timedelta) -> str:
"""Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S'
Expand Down Expand Up @@ -959,7 +963,7 @@ def _failsafe_deserialize(

def _failsafe_deserialize_xml(
deserializer: typing.Any,
response: HttpResponse,
response: HttpResponse,
) -> typing.Any:
try:
return _deserialize_xml(deserializer, response.text())
Expand Down Expand Up @@ -1208,7 +1212,7 @@ def _deserialize_xml(
deserializer: typing.Any,
value: str,
) -> typing.Any:
element = ET.fromstring(value) # nosec
element = etree.fromstring(value, parser=_XML_PARSER)
return _deserialize(deserializer, element)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ try:
from urllib import quote # type: ignore
except ImportError:
from urllib.parse import quote
import lxml.etree as etree
import xml.etree.ElementTree as ET

import isodate # type: ignore
Expand All @@ -44,6 +45,9 @@ _BOM = codecs.BOM_UTF8.decode(encoding="utf-8")

JSON = MutableMapping[str, Any]

_XML_PARSER = etree.XMLParser(resolve_entities=False)
"""Avoid XML entity resolution to prevent XXE attacks. (https://github.com/microsoft/typespec/issues/8083)"""


class RawDeserializer:

Expand Down Expand Up @@ -98,7 +102,7 @@ class RawDeserializer:
except NameError:
pass

return ET.fromstring(data_as_str) # nosec
return etree.fromstring(data_as_str, parser=_XML_PARSER)
except ET.ParseError as err:
# It might be because the server has an issue, and returned JSON with
# content-type XML....
Expand Down
1 change: 1 addition & 0 deletions packages/http-client-python/generator/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@
"PyYAML==6.0.1",
"tomli==2.0.1",
"setuptools==75.3.2",
"lxml>=6.0,<7.0"
],
)
Loading