Critical severity9.0NVD Advisory· Published Mar 3, 2017· Updated May 13, 2026
CVE-2016-10127
CVE-2016-10127
Description
PySAML2 allows remote attackers to conduct XML external entity (XXE) attacks via a crafted SAML XML request or response.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pysaml2PyPI | < 4.5.0 | 4.5.0 |
Patches
16e09a25d9b4bFix XXE in XML parsing (related to #366)
7 files changed · +95 −6
setup.py+1 −0 modified@@ -18,6 +18,7 @@ 'pytz', 'pyOpenSSL', 'python-dateutil', + 'defusedxml', 'six' ]
src/saml2/__init__.py+3 −2 modified@@ -36,6 +36,7 @@ import cElementTree as ElementTree except ImportError: from elementtree import ElementTree +import defusedxml.ElementTree root_logger = logging.getLogger(__name__) root_logger.level = logging.NOTSET @@ -87,7 +88,7 @@ def create_class_from_xml_string(target_class, xml_string): """ if not isinstance(xml_string, six.binary_type): xml_string = xml_string.encode('utf-8') - tree = ElementTree.fromstring(xml_string) + tree = defusedxml.ElementTree.fromstring(xml_string) return create_class_from_element_tree(target_class, tree) @@ -269,7 +270,7 @@ def loadd(self, ava): def extension_element_from_string(xml_string): - element_tree = ElementTree.fromstring(xml_string) + element_tree = defusedxml.ElementTree.fromstring(xml_string) return _extension_element_from_element_tree(element_tree)
src/saml2/pack.py+2 −1 modified@@ -37,6 +37,7 @@ import cElementTree as ElementTree except ImportError: from elementtree import ElementTree +import defusedxml.ElementTree NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/" FORM_SPEC = """<form method="post" action="%s"> @@ -235,7 +236,7 @@ def parse_soap_enveloped_saml(text, body_class, header_class=None): :param text: The SOAP object as XML :return: header parts and body as saml.samlbase instances """ - envelope = ElementTree.fromstring(text) + envelope = defusedxml.ElementTree.fromstring(text) assert envelope.tag == '{%s}Envelope' % NAMESPACE # print(len(envelope))
src/saml2/soap.py+4 −3 modified@@ -19,6 +19,7 @@ except ImportError: #noinspection PyUnresolvedReferences from elementtree import ElementTree +import defusedxml.ElementTree logger = logging.getLogger(__name__) @@ -133,7 +134,7 @@ def parse_soap_enveloped_saml_thingy(text, expected_tags): :param expected_tags: What the tag of the SAML thingy is expected to be. :return: SAML thingy as a string """ - envelope = ElementTree.fromstring(text) + envelope = defusedxml.ElementTree.fromstring(text) # Make sure it's a SOAP message assert envelope.tag == '{%s}Envelope' % soapenv.NAMESPACE @@ -183,7 +184,7 @@ def class_instances_from_soap_enveloped_saml_thingies(text, modules): :return: The body and headers as class instances """ try: - envelope = ElementTree.fromstring(text) + envelope = defusedxml.ElementTree.fromstring(text) except Exception as exc: raise XmlParseError("%s" % exc) @@ -209,7 +210,7 @@ def open_soap_envelope(text): :return: dictionary with two keys "body"/"header" """ try: - envelope = ElementTree.fromstring(text) + envelope = defusedxml.ElementTree.fromstring(text) except Exception as exc: raise XmlParseError("%s" % exc)
tests/test_03_saml2.py+27 −0 modified@@ -17,6 +17,7 @@ import cElementTree as ElementTree except ImportError: from elementtree import ElementTree +from defusedxml.common import EntitiesForbidden ITEMS = { NameID: ["""<?xml version="1.0" encoding="utf-8"?> @@ -166,6 +167,19 @@ def test_create_class_from_xml_string_wrong_class_spec(): assert kl == None +def test_create_class_from_xml_string_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(EntitiesForbidden) as err: + create_class_from_xml_string(NameID, xml) + + def test_ee_1(): ee = saml2.extension_element_from_string( """<?xml version='1.0' encoding='UTF-8'?><foo>bar</foo>""") @@ -454,6 +468,19 @@ def test_ee_7(): assert nid.text.strip() == "http://federationX.org" +def test_ee_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(EntitiesForbidden): + saml2.extension_element_from_string(xml) + + def test_extension_element_loadd(): ava = {'attributes': {}, 'tag': 'ExternalEntityAttributeAuthority',
tests/test_43_soap.py+43 −0 modified@@ -12,9 +12,13 @@ import cElementTree as ElementTree except ImportError: from elementtree import ElementTree +from defusedxml.common import EntitiesForbidden + +from pytest import raises import saml2.samlp as samlp from saml2.samlp import NAMESPACE as SAMLP_NAMESPACE +from saml2 import soap NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/" @@ -66,3 +70,42 @@ def test_make_soap_envelope(): assert len(body) == 1 saml_part = body[0] assert saml_part.tag == '{%s}AuthnRequest' % SAMLP_NAMESPACE + + +def test_parse_soap_enveloped_saml_thingy_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(EntitiesForbidden): + soap.parse_soap_enveloped_saml_thingy(xml, None) + + +def test_class_instances_from_soap_enveloped_saml_thingies_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(soap.XmlParseError): + soap.class_instances_from_soap_enveloped_saml_thingies(xml, None) + + +def test_open_soap_envelope_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(soap.XmlParseError): + soap.open_soap_envelope(xml)
tests/test_51_client.py+15 −0 modified@@ -7,6 +7,7 @@ from future.backports.urllib.parse import parse_qs from future.backports.urllib.parse import urlencode from future.backports.urllib.parse import urlparse +from pytest import raises from saml2.argtree import add_path from saml2.cert import OpenSSLWrapper @@ -25,6 +26,7 @@ from saml2.authn_context import INTERNETPROTOCOLPASSWORD from saml2.client import Saml2Client from saml2.config import SPConfig +from saml2.pack import parse_soap_enveloped_saml from saml2.response import LogoutResponse from saml2.saml import NAMEID_FORMAT_PERSISTENT, EncryptedAssertion, Advice from saml2.saml import NAMEID_FORMAT_TRANSIENT @@ -38,6 +40,8 @@ from saml2.s_utils import factory from saml2.time_util import in_a_while, a_while_ago +from defusedxml.common import EntitiesForbidden + from fakeIDP import FakeIDP from fakeIDP import unpack_form from pathutils import full_path @@ -1552,6 +1556,17 @@ def test_negotiated_post_sso(self): 'http://www.example.com/login' assert ac.authn_context_class_ref.text == INTERNETPROTOCOLPASSWORD +def test_parse_soap_enveloped_saml_xxe(): + xml = """<?xml version="1.0"?> + <!DOCTYPE lolz [ + <!ENTITY lol "lol"> + <!ELEMENT lolz (#PCDATA)> + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> + ]> + <lolz>&lol1;</lolz> + """ + with raises(EntitiesForbidden): + parse_soap_enveloped_saml(xml, None) # if __name__ == "__main__": # tc = TestClient()
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/rohe/pysaml2/commit/6e09a25d9b4b7aa7a506853210a9a14100b8bc9bnvdPatchWEB
- github.com/rohe/pysaml2/issues/366nvdIssue TrackingPatchWEB
- github.com/rohe/pysaml2/pull/379nvdIssue TrackingPatchWEB
- www.openwall.com/lists/oss-security/2017/01/19/5nvdMailing ListThird Party AdvisoryWEB
- bugs.debian.org/cgi-bin/bugreport.cginvdMailing ListThird Party AdvisoryWEB
- github.com/advisories/GHSA-m269-wj6g-c459ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-10127ghsaADVISORY
- www.securityfocus.com/bid/95376nvdVDB Entry
- github.com/pypa/advisory-database/tree/main/vulns/pysaml2/PYSEC-2017-67.yamlghsaWEB
- web.archive.org/web/20200227195127/http://www.securityfocus.com/bid/95376ghsaWEB
News mentions
0No linked articles in our index yet.