XML Entity Expansion in Ruby
Vulnerable example
Consider the following vulnerable Ruby on Rails example, which uses the Nokogiri
library to parse the XML. Assume there is a builder in the background forming the XML response from the @response
variable.
@response = Nokogiri::XML(request.body) do |config|
config.strict.noent
end
The way in which the parser is configured introduces an XML Entity Expansion vulnerability, which can be exploited by sending a specially crafted XML document to expose arbitrary files; for example, /etc/passwd
.
<!DOCTYPE doc [ <!ELEMENT elem ANY><!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<element>Legitimate Data&xxe;</element>
Note the above example inserts the xxe
entity within the element
. In some use cases, an XML response will use elements from the request; therefore, it is insufficient to solely filter out unwanted elements.
Prevention
The noent
option configures Nokogiri
to expand entities, introducing the vulnerability. In many XML parsing libraries, including Nokogiri
, the default is to not do so. However, they may be configured to expand entities, such as in the example above with the noent
option.
To remediate this, it is best to explicitly disable entity expansion; defaults may change.
The fixed code below parses XML safely by disabling entity expansion with the nonoent
option.
@response = Nokogiri::XML(request.body) do |config|
config.strict.nonoent
end
References
OWASP - XML External Entity (XXE) Processing OWASP - XML External Entity Prevention Cheat Sheet