HIGH xml external entitieshapifirestore

Xml External Entities in Hapi with Firestore

Xml External Entities in Hapi with Firestore — how this specific combination creates or exposes the vulnerability

An XML External Entity (XXE) attack occurs when an XML processor discloses internal files or triggers network calls via malicious external entity definitions. In a Hapi server, if user-controlled data is parsed as XML and the parser is configured to resolve external entities, an attacker can coerce the server to read local files, reach internal endpoints, or cause denial of service. When Firestore is used as the backend, the risk is not that Firestore itself parses XML, but that a Hapi service deserializes XML input (for example, from an HTTP payload or an uploaded file) and then uses Firestore operations based on that data. If the XML contains external entity references, the server may disclose configuration or source files that include Firestore project settings, service account key paths, or environment variables that affect Firestore access. An attacker can also leverage XXE to perform SSRF against internal Firestore metadata endpoints or service metadata, potentially inferring project structure or service permissions. Because Firestore rules and IAM policies are often defined with project-specific context, leaking server-side paths or service account details can make it easier to craft authenticated attacks against the database. In a typical API flow, a Hapi route might accept an XML upload, parse it with an unsafe XML parser, and then write values into Firestore. If the parser resolves DOCTYPE declarations and external entities, the server can be tricked into reading files such as /etc/passwd or local instance metadata that may contain sensitive configuration related to Firestore authentication. This combination therefore exposes the vulnerability through insecure XML handling in Hapi rather than through Firestore itself, but the impact is amplified when Firestore holds sensitive project data.

Firestore-Specific Remediation in Hapi — concrete code fixes

To prevent XXE in Hapi when working with Firestore, ensure XML parsing is either disabled or configured to disallow external entities. Use a well-maintained XML parser with secure defaults and avoid legacy or permissive options that resolve DOCTYPEs. The following examples show safe approaches for Hapi routes that may receive XML input.

Example 1: Reject or sanitize XML input

If your API does not need XML, reject XML content types early:

const Hapi = require('@hapi/hapi');

const init = async () => {
  const server = Hapi.server({ port: 4000, host: 'localhost' });

  server.route({
    method: 'POST',
    path: '/submit',
    options: {
      parse: {
        payload: false // Disable parsing to avoid processing XML
      },
      handler: (request, h) => {
        // Expect JSON only
        const { data } = request.payload;
        // Validate and use Firestore SDK with trusted data
        return { status: 'ok' };
      }
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

Example 2: Secure XML parsing with an XML parser that disables external entities

If you must process XML, use a parser that disables external entities. For example, with libxmljs (Node.js), configure the parser securely:

const Hapi = require('@hapi/hapi');
const libxmljs = require('libxmljs');

const init = async () => {
  const server = Hapi.server({ port: 4000, host: 'localhost' });

  server.route({
    method: 'POST',
    path: '/parse-xml',
    options: {
      parse: {
        payload: true
      },
      handler: (request, h) => {
        const xmlPayload = request.payload.toString();
        try {
          // Parse XML without loading external entities
          const doc = libxmljs.parseXml(xmlPayload, {
            noblanks: true,
            noent: false,
            nocdata: false,
            forbidExternalEntities: true // Disable external entities
          });
          // Extract only needed data and validate before Firestore operations
          const title = doc.get('//title/text()') ? doc.get('//title/text()').value() : null;
          if (!title) {
            throw new Error('Missing required field');
          }
          // Safe Firestore usage with trusted, validated data
          // const docRef = firestore.collection('items').doc();
          // await docRef.set({ title });
          return { message: 'XML processed safely', title };
        } catch (err) {
          throw Boom.badRequest('Invalid or unsafe XML: ' + err.message);
        }
      }
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

Example 3: Firestore write with validated, non-XML data

After validating input, interact with Firestore using the official SDK. Keep sensitive configuration server-side and avoid echoing raw user input into Firestore paths or document fields:

const Hapi = require('@hapi/hapi');
const admin = require('firebase-admin');

// Initialize Firestore securely using environment-bound credentials
admin.initializeApp({
  credential: admin.credential.applicationDefault()
});
const firestore = admin.firestore();

const init = async () => {
  const server = Hapi.server({ port: 4000, host: 'localhost' });

  server.route({
    method: 'POST',
    path: '/items',
    options: {
      parse: {
        payload: true
      },
      handler: async (request, h) => {
        const { name, value } = request.payload;
        // Validate and sanitize inputs
        if (typeof name !== 'string' || name.trim().length === 0) {
          throw Boom.badRequest('Invalid name');
        }
        if (typeof value !== 'number') {
          throw Boom.badRequest('Value must be a number');
        }
        // Write validated data to Firestore
        const docRef = firestore.collection('items').doc();
        await docRef.set({ name: name.trim(), value, createdAt: admin.firestore.FieldValue.serverTimestamp() });
        return { id: docRef.id, status: 'created' };
      }
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init();

Additional hardening tips

  • Do not log raw XML payloads or Firestore credentials in production.
  • Apply strict content-type validation and size limits on incoming payloads.
  • Use Firestore IAM and rules to enforce least privilege; do not rely on parsing logic alone for security decisions.
  • Keep server-side libraries and the Firestore SDK up to date to avoid known parser vulnerabilities.

Frequently Asked Questions

Can an XXE attack against a Hapi service lead to Firestore credential exposure?
Yes, if the Hapi server parses untrusted XML with external entity resolution enabled, it may read server-side files that contain Firestore service account keys or project configuration, potentially exposing credentials.
Does middleBrick detect XXE risks in API payload parsing?
middleBrick runs security checks such as Input Validation and Unsafe Consumption as part of its 12 parallel scans. While it identifies risky parsing behaviors and provides remediation guidance, it does not modify or block requests; findings should be reviewed and fixed in your service code.