Xml External Entities in Grape with Bearer Tokens
Xml External Entities in Grape with Bearer Tokens — how this specific combination creates or exposes the vulnerability
XML External Entity (XXE) injection occurs when an XML parser processes external entity references in a way that can disclose local files, trigger SSRF, or lead to denial of service. Grape is a Ruby REST micro-framework that often parses XML payloads when clients send Content-Type application/xml. When Grape APIs accept bearer tokens—typically passed in the Authorization header as Bearer
The combination exposes a risk pattern: an attacker sends a crafted XML body with external entity definitions and a file:// or http:// URI in a parameter, while including a Bearer token in the header. If the Grape app parses the XML unsafely (for example, using a default Nokogiri::XML parser without disabling external entities), the parser may follow the external reference. This can read files such as /etc/passwd (file:///etc/passwd) or make internal HTTP requests to metadata services (http://169.254.169.254/latest/meta-data/), potentially exfiltrating secrets or probing internal infrastructure. The presence of a Bearer token does not prevent file or SSRF-based XXE; it may simply indicate an authenticated context that gives an attacker more stable access to internal endpoints once a path is found.
MiddlewareBrick scans include an Input Validation check that flags unsafe XML parsing configurations and an SSRF check that detects attempts to reach internal IPs via external entities. In a real scan, you might find findings such as "XML parser allows external entity expansion" mapped to OWASP API Top 10 A03:2023 — Injection, and mapped to PCI-DSS and SOC2 controls. The scanner submits XML payloads designed to trigger entity expansion and inspects responses for evidence such as file contents or internal host reachability, without requiring authentication to demonstrate the vulnerability if the endpoint is unauthenticated. Even when Bearer tokens are required, the presence of the token does not mitigate a server-side XXE misconfiguration; it only changes the trust boundary around the impact.
Bearer Tokens-Specific Remediation in Grape — concrete code fixes
To secure Grape endpoints that accept Bearer tokens and may receive XML payloads, disable external entity processing in the XML parser and avoid passing raw user input into XML construction. Below are concrete code examples showing insecure and secure configurations.
Insecure Grape endpoint (vulnerable to XXE)
require 'grape'
require 'nokogiri'
class VulnerableAPI < Grape::API
format :xml
content_type :xml, 'application/xml'
before { header['WWW-Authenticate'] = 'Bearer realm="api"' if !env['HTTP_AUTHORIZATION'].to_s.start_with?('Bearer ') }
# This endpoint naïvely parses XML without disabling external entities
post :submit do
# WARNING: Nokogiri::XML() without options allows external entities by default in some configurations
doc = Nokogiri::XML(request.body.read)
# Example unsafe usage: extracting a value that could be controlled via an external entity
extracted = doc.at_xpath('//data')&.text
{ received: extracted }.to_json
end
end
Secure Grape endpoint with Bearer token validation and XXE prevention
require 'grape'
require 'nokogiri'
class SecureAPI < Grape::API
format :xml
content_type :xml, 'application/xml'
helpers do
# Validate Bearer token presence and format
def authenticate_bearer!
auth = env['HTTP_AUTHORIZATION']
unless auth.to_s.start_with?('Bearer ')
error!({ error: 'unauthorized', message: 'Missing or invalid Bearer token' }, 401)
end
token = auth.split(' ').last
# Replace with your token validation logic (e.g., JWT verify, DB lookup)
error!({ error: 'forbidden', message: 'Invalid token' }, 403) unless valid_token?(token)
end
def valid_token?(token)
# Stub: implement proper validation (e.g., JWT decode/verify, revocation check)
token == 'expected-secure-token-example'
end
end
before { authenticate_bearer! }
# Secure parsing: disable DTD and external entities
post :submit do
# Use Nokogiri::XML with security options to prevent XXE
parser_options = {
noent: false, # Disable entity expansion
external: false, # Disable external general entities
internal_subset: nil # Do not inject an internal subset
}
doc = Nokogiri::XML(request.body.read, nil, nil, parser_options)
# Safe extraction: no resolution of external entities
extracted = doc.at_xpath('//data')&.text
{ received: extracted }.to_json
end
end
Additional server-side protections
- Apply the same parser options if you use REXML or other XML libraries; for example, with REXML ensure DTD and external references are not resolved.
- Keep XML parsing minimal: prefer JSON for new APIs, or use strict schema validation (XSD or RelaxNG) and whitelisted element names.
- Ensure sensitive files and internal metadata endpoints are not reachable from the application network, and apply network-level restrictions to reduce the impact of any residual SSRF/XXE paths.
When using MiddleBrick, the CLI (middlebrick scan <url>) and Web Dashboard can surface these XXE findings with severity levels and remediation guidance, while the GitHub Action can gate CI/CD if a risk score drops below your chosen threshold. The MCP Server lets you trigger scans directly from your AI coding assistant to catch unsafe parsers before code merges.