Skip to content

Commit

Permalink
Fix external entities vulnerability (#35)
Browse files Browse the repository at this point in the history
* Fix external entities vulnerability

xml.sax is vulnerable to external entities & expansion.
Take a dependency on the defusedxml module, which provides the same interface.

Thanks to @KevinHock
  • Loading branch information
KevinHock authored and ellieayla committed Nov 22, 2017
1 parent 95d31b4 commit d69a73c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
defusedxml>=0.5.0
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from setuptools import setup

setup(name='pyforce',
version='1.7.3', # be sure to update the version in pyforce.py too
version='1.8.0',
install_requires=['defusedxml>=0.5.0'],
package_dir={'': 'src'},
packages=['pyforce'],
author = "Simon Fell et al. reluctantly Forked by idbentley",
Expand Down
26 changes: 25 additions & 1 deletion src/pyforce/xmltramp.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""xmltramp: Make XML documents easily accessible."""

import defusedxml
from xml.sax.handler import EntityResolver, DTDHandler, ContentHandler,\
ErrorHandler
from xml.sax import make_parser
from defusedxml.sax import make_parser
from xml.sax.handler import feature_namespaces

__version__ = "2.18"
Expand Down Expand Up @@ -475,5 +476,28 @@ def unittest():
'<a xmlns="http://a"><b xmlns="http://b"/></a>'
).__repr__(1) == '<a xmlns="http://a"><b xmlns="http://b"></b></a>'

# This uses internal entities to DoS vulnerable XML parsers
evil_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;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>"""
try:
assert parse(evil_xml)
# It never gets here and instead raises a defusedxml.common.EntitiesForbidden exception
assert False
except defusedxml.common.EntitiesForbidden:
assert True

if __name__ == '__main__':
unittest()

0 comments on commit d69a73c

Please sign in to comment.