XML external entity expansion¶
ID: rb/xxe
Kind: path-problem
Security severity: 9.1
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-611
- external/cwe/cwe-776
- external/cwe/cwe-827
Query suites:
- ruby-code-scanning.qls
- ruby-security-extended.qls
- ruby-security-and-quality.qls
Click to see the query in the CodeQL repository
Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible and out-of-band data retrieval techniques may allow attackers to steal sensitive data.
Recommendation¶
The easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as rexml
, nokogiri
and libxml-ruby
, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.
Example¶
The following example uses the nokogiri
XML parser to parse a string xmlSrc
. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is invoked with the noent
option set:
require "nokogiri"
def process_data1
xmlSrc = request.body
doc = Nokogiri::XML.parse(xmlSrc, nil, nil, Nokogiri::XML::ParseOptions::NOENT) # BAD
end
def process_data2
xmlSrc = request.body
doc = Nokogiri::XML.parse(xmlSrc) { |config| config.noent } # BAD
end
To guard against XXE attacks, the noent
option should be omitted or cleared (e.g. using nonoent
). This means that no entity expansion is undertaken at all, not even for standard internal entities such as &
or >
. If desired, these entities can be expanded in a separate step using utility functions.
require "nokogiri"
def process_data1
xmlSrc = request.body
doc = Nokogiri::XML.parse(xmlSrc) # GOOD
end
def process_data2
xmlSrc = request.body
doc = Nokogiri::XML.parse(xmlSrc) { |config| config.nonoent } # GOOD
end
References¶
Timothy Morgen: XML Schema, DTD, and Entity Attacks.
Timur Yunusov, Alexey Osipov: XML Out-Of-Band Data Retrieval.
Common Weakness Enumeration: CWE-611.
Common Weakness Enumeration: CWE-776.
Common Weakness Enumeration: CWE-827.