
Исполняемый proof-of-concept для воспроизведения CVE-2026-88789, демонстрирующий XXE и SSRF в Apache Camel Quarkus camel-quarkus-support-xalan через XSLT TransformerFactory.
TransformerFactory отменяет ограничения JAXP на внешний доступЗапускаемый proof-of-concept репродуктор уязвимости Apache Camel Quarkus, при которой расширение поддержки XSLT
(camel-quarkus-support-xalan) предоставляет собственный TransformerFactory на базе Xalan для компонента xslt
и регистрирует его как JAXP-реализацию по умолчанию. Xalan-J 2.7.x предшествует JAXP 1.5 и не может соблюдать
javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD или ACCESS_EXTERNAL_STYLESHEET — setAttribute() выбрасывает
IllegalArgumentException для обоих — поэтому ограничения внешнего доступа, которые Apache Camel применяет к
создаваемому им TransformerFactory, никогда не действовали.
| Среда выполнения | Каталог | Стек |
|---|---|---|
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.36.0 (Quarkus 3.36.0, Camel 4.20.0) |
Только Camel Quarkus. Уязвимый код — это расширение Camel Quarkus, а не компонент Camel. Обычный Camel и Camel Spring Boot используют
TransformerFactoryиз JDK, который соблюдает оба атрибута, поэтому воспроизводить там нечего — по этой причине в этом репозитории нет вариантаcamel-spring-boot/.
Злоумышленник, предоставляющий преобразуемый XML-документ, может читать локальные файлы или обращаться к внутренним сетевым ресурсам через объявление внешней сущности в этом документе.
cd camel-quarkus
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Ожидаемый вывод на уязвимой сборке (сокращённо — драйвер выполняет шесть проверок, см.
camel-quarkus/README.md):
1) xslt endpoint, body is a StreamSource, external entity -> file:///tmp/cve-2026-88789-secrets/db-password.txt
transformation result: [db.password=LOCAL-FILE-s3cr3t-99]
local file contents in the output: true
2) xslt endpoint, body is a StreamSource, external entity -> http://127.0.0.1:8080/internal/secret
transformation result: [INTERNAL-SECRET-s3cr3t-42]
internal endpoint response in the output: true
4) CONTROL - same document as a String body (Camel converts it to a SAXSource itself)
transformation result: []
local file contents in the output: false
5) TransformerFactory.newInstance() anywhere in the application
factory: org.apache.camel.quarkus.support.xalan.XalanTransformerFactory
setAttribute(ACCESS_EXTERNAL_DTD, ""): REFUSED, IllegalArgumentException: ...
identity transform of the same document: [... <data>db.password=LOCAL-FILE-s3cr3t-99</data> ...]
Requests the XML parser made to internal endpoints on its own: [GET /internal/secret, GET /internal/leak.dtd]
>>> PROVEN: ...
Проверено также на Camel Quarkus 3.40.0: все утечки в проверках исчезают, внутренние эндпоинты
не получают ни одного запроса, а драйвер выводит NOT reproduced.
На пути компонента xslt затронуты только тела, которые достигают трансформера уже как
javax.xml.transform.Source. Тела других типов — String, byte[], InputStream — преобразуются
Apache Camel в SAXSource с отключённой загрузкой внешних сущностей и внешних DTD и не затронуты.
Проверка 4 в репродукторе — это безопасный путь, рядом с небезопасным.
Поскольку фабрика также регистрируется как JAXP-реализация по умолчанию (расширение поддержки поставляет
META-INF/services/javax.xml.transform.TransformerFactory), любой другой код в приложении, получающий
фабрику через TransformerFactory.newInstance(), теряет те же ограничения без каких-либо ошибок. Именно
поэтому в рекомендациях перечислены расширения, которые сами ничего не преобразуют:
| Расширение | Подверженность |
|---|---|
camel-quarkus-xslt | путь компонента xslt и JAXP-реализация по умолчанию |
camel-quarkus-xslt-saxon | JAXP-реализация по умолчанию |
camel-quarkus-tika | JAXP-реализация по умолчанию |
camel-quarkus-xmlsecurity | JAXP-реализация по умолчанию |
| Свойство | Значение |
|---|---|
| Компонент | camel-quarkus-support-xalan (расширение поддержки XSLT) |
| CWE | CWE-611 (Ненадлежащее ограничение ссылок на внешние XML-сущности) |
| Критичность | Высокая |
| Вектор атаки | Внешняя сущность или внешний DTD, объявленные в преобразуемом XML-документе, где тело достигает эндпоинта xslt уже как javax.xml.transform.Source |
| Воздействие | Чтение локальных файлов; выполнение запросов к внутренним сетевым ресурсам (SSRF) |
| Уязвимые версии | С 3.2.0 до 3.33.3, с 3.34.0 до 3.40.0 |
| Исправленные версии | 3.33.3 (ветка LTS), 3.40.0 |
| GitHub issue | apache/camel-quarkus#9115 |
| Благодарность | Обнаружено в ходе внутреннего анализа с использованием Claude Security Tool |
Рекомендация: https://camel.apache.org/security/CVE-2026-88789.html
XalanTransformerFactory теперь применяет ограничения самостоятельно, вместо того чтобы полагаться на
атрибуты, которые Xalan не может соблюдать:
XMLReader, который не разрешает ни внешние общие, ни
внешние параметрические сущности и не загружает внешние DTD — та же конфигурация, которую использует
XmlConverter.createSAXParserFactory() из Apache Camel для тел, которые camel-xslt сам преобразует в
SAXSource. SAXSource, несущий настроенный вызывающей стороной XMLReader, используется как есть, а
DOMSource и StAXSource уже разобраны.document(), запрещены, если только их не разрешает
собственный URIResolver приложения, и это ограничение устанавливается на каждой точке входа, которая
предоставляет что-либо для преобразования, включая точки входа SAX push, на трансформеры которых Xalan не
копирует резолвер фабрики. Приложения, устанавливающие собственный резолвер — camel-xslt делает это на
каждом обмене — по-прежнему переопределяют его, как и раньше.Исправлено в ветке main в
9a570b64 и
9dd11779,
перенесено в 3.33.x в
ad9c5236 и
3d886769.
javax.xml.transform.Source, построенный из недоверенных входных данных, в эндпоинт xslt.
Оставляйте тело сообщения как String, byte[] или InputStream, чтобы Apache Camel сначала преобразовал
его в SAXSource с отключёнными внешними сущностями.convertBodyTo для существующего тела типа Source — не обходной путь: это преобразование выполняет
identity-преобразование через ту же фабрику. Проверка 5 в репродукторе — это и есть identity-преобразование,
и оно приводит к утечке.com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl,
вместо того чтобы полагаться на TransformerFactory.newInstance(). Проверка 6 — это контроль, и она
запрещает чтение.Этот репозиторий опубликован в образовательных и защитных целях: чтобы помочь пользователям Apache Camel Quarkus понять уязвимость, проверить, затронуты ли они, и убедиться, что обновление её устраняет. Не используйте этот материал против систем, которыми вы не владеете и не управляете.