Xml External Entities in Grape with Mutual Tls
Xml External Entities in Grape with Mutual Tls — how this specific combination creates or exposes the vulnerability
XML External Entity (XXE) injection is a web application security issue that occurs when an application parses XML input and allows an attacker to define external entities. In a Grape API, this typically arises when the request body is parsed as XML and the parser is configured to resolve external references. Grape, being a Ruby web framework for building REST-like APIs, often uses libraries such as nokogiri or rexml for XML processing. If the parser is not hardened, an attacker can supply an XML payload that references local files (e.g., file:///etc/passwd) or remote endpoints, leading to data exposure, server-side request forgery, or denial of service.
Mutual Transport Layer Security (Mutual TLS) adds client certificate authentication on top of standard TLS. With Mutual TLS enabled, clients must present a valid certificate trusted by the server before the application layer processes any request. While Mutual TLS strengthens authentication and helps prevent unauthorized clients from reaching the Grape endpoint, it does not inherently protect against XXE if the endpoint accepts and parses XML from authenticated clients. In other words, once a Mutual TLS-authenticated client is allowed to send requests, the XML parsing path remains a potential vector if the parser resolves external entities. An authorized client—such as a compromised microservice or a malicious insider with valid credentials—can still submit crafted XML that triggers XXE behavior.
The combination of XXE and Mutual TLS can expose subtle operational risks. Because Mutual TLS ensures only authenticated clients connect, developers and security teams may assume the request surface is safe, potentially relaxing input validation and parser hardening. This false sense of security can lead to overlooking XML parser configuration. Additionally, in environments where Mutual TLS is used for service-to-service communication, XML payloads may be accepted from trusted partners; if those partners’ systems are compromised or their APIs are misconfigured, an attacker could leverage trusted channels to deliver XXE payloads. Therefore, the presence of Mutual TLS does not mitigate XXE and should not reduce the need for secure XML parsing practices within Grape.
middleBrick scans unauthenticated attack surfaces and, when applicable, can detect indicators of insecure XML handling such as verbose error messages or unexpected behavior when probing endpoints that accept XML. Its checks include input validation and data exposure tests that map to OWASP API Top 10 and can surface weaknesses in how XML is processed, regardless of the transport-level protections in place.
Mutual Tls-Specific Remediation in Grape — concrete code fixes
To remediate XXE in Grape while using Mutual TLS, focus on hardening the XML parser and ensuring that request handling does not enable external entity resolution. Below are concrete code examples for a secure Grape configuration.
Disable external entity resolution in Nokogiri
If you use Nokogiri for XML parsing, configure it to disallow external entities. Here is an example of a Grape API that safely parses XML without resolving external references:
require 'grape'
require 'nokogiri'
class SecureApi < Grape::API
format :xml
before do
# Enforce Mutual TLS by ensuring the request client certificate is validated
# (This is typically handled at the web server or Rack layer, not in Grape directly.)
# Ensure the environment contains verified client certificate details.
error!('Unauthorized', 401) unless env['SSL_CLIENT_VERIFY'] == 'SUCCESS'
end
resource :data do
desc 'Accept XML securely, with XXE protections'
params do
requires :xml_body, type: String, desc: 'XML payload as a string'
end
post do
xml_input = declared(params[:xml_body], type: String)
# Parse with external subset and general entities disabled
parser = Nokogiri::XML::SAX::Parser.new(SecureXmlHandler.new)
parser.parse(xml_input, nil, &nil) # No external subset or system URIs
# Alternatively, use Nokogiri::XML with safe options:
# doc = Nokogiri::XML(xml_input) do |config|
# config.noblanks
# config.strict
# config.options = Nokogiri::XML::ParseOptions::NOENT | Nokogiri::XML::ParseOptions::NONET
# end
# However, prefer SAX with a custom handler for maximum control.
{ status: 'ok', received: true }
end
end
end
class SecureXmlHandler < Nokogiri::XML::SAX::Document
def start_element(name, attrs = [])
# Process elements safely; avoid expanding entities
end
end
Use secure alternatives and input validation
If you do not need XML features, consider using JSON instead. If XML is required, avoid REXML for untrusted input and validate structure strictly. Here is an example of rejecting requests that attempt to include external entity declarations:
require 'grape'
class ValidatingApi < Grape::API
format :xml
before do
error!('Unauthorized', 401) unless env['SSL_CLIENT_VERIFY'] == 'SUCCESS'
end
resource :submit do
desc 'Reject XML with external entity references'
params do
requires :payload, type: String, desc: 'XML string'
end
post do
body = declared(params[:payload])
if body.include?('
Web server and middleware configuration
Mutual TLS is commonly enforced at the web server or load balancer (e.g., Nginx, HAProxy). Ensure that the server is configured to require client certificates and that the Grape app only receives requests after successful client authentication. Also ensure the XML parser settings align with security best practices, such as disabling DTD processing and external network access.
| Control | Description | Implementation Example |
|---|---|---|
| Disable external entities | Configure parser to not resolve external subsets or system URIs | parser.parse(xml_input, nil, &nil) with a SAX parser that ignores external entities |
| Validate client certificates | Ensure the request includes a verified client certificate | Grape receives this via the environment after the TLS layerenv['SSL_CLIENT_VERIFY'] == 'SUCCESS' before processing |
| Input validation | \nReject XML containing entity declarations | \nCheck for <!ENTITY, SYSTEM, or PUBLIC substrings | \n
By combining these measures, you maintain the authentication benefits of Mutual TLS while specifically mitigating XXE risks in Grape. Remember that middleBrick’s scans can help verify that your endpoints do not exhibit signs of insecure XML handling, complementing these code-level fixes.