Skip to content
Exploit for CVE-2026

Exploit for CVE-2026

Sploitus • October 1, 2026

# CVE-2026-88789 — Camel Quarkus: forced Xalan `TransformerFactory` drops the JAXP external access restrictions

Runnable proof-of-concept reproducer for the Apache Camel Quarkus vulnerability where the XSLT support

extension (`camel-quarkus-support-xalan`) supplies its own Xalan-backed `TransformerFactory` to the `xslt`

component and registers it as the JAXP default. Xalan-J 2.7.x predates JAXP 1.5 and cannot honour

`javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD` or `ACCESS_EXTERNAL_STYLESHEET` — `setAttribute()` throws

`IllegalArgumentException` for both — so the external access restrictions Apache Camel applies to the

`TransformerFactory` it creates were never in effect.

| **Camel Quarkus** | [`camel-quarkus/`](camel-quarkus/) | Camel Quarkus **3.36.0** (Quarkus 3.36.0, Camel 4.20.0) |

> **Camel Quarkus only.** The vulnerable code is a Camel Quarkus extension, not a Camel component. Plain

> Camel and Camel Spring Boot use the JDK's `TransformerFactory`, which honours both attributes, so there is

> nothing to reproduce there — this repository therefore has no `camel-spring-boot/` variant.

An attacker who supplies the XML document being transformed can read local files or reach internal network

locations through an external entity declaration in that document.

curl -s

Expected output on an affected build (abridged — the driver runs six probes, see

[`camel-quarkus/README.md`](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]

2) xslt endpoint, body is a StreamSource, external entity ->

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)

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: [... db.password=LOCAL-FILE-s3cr3t-99 ...]

Requests the XML parser made to internal endpoints on its own: [GET /internal/secret, GET /internal/leak.dtd]

Verified against Camel Quarkus **3.40.0** as well: every leaking probe goes quiet, the internal endpoints

receive no requests at all, and the driver prints `NOT reproduced`.

On the `xslt` component path, only bodies that reach the transformer **already as a

`javax.xml.transform.Source`** are affected. Bodies of other types — `String`, `byte[]`, `InputStream` — are

converted by Apache Camel to a `SAXSource` with external entities and external DTD loading disabled, and are

not affected. Probe 4 in the reproducer is that safe path, side by side with the unsafe one.

Because the factory is also registered as the **JAXP default** (the support extension ships

`META-INF/services/javax.xml.transform.TransformerFactory`), any other code in the application that obtains

a factory through `TransformerFactory.newInstance()` loses the same restrictions, without an error. That is

why the advisory lists extensions that never transform anything themselves:

| `camel-quarkus-xslt` | the `xslt` component path **and** the JAXP default |

| `camel-quarkus-xslt-saxon` | the JAXP default |

| `camel-quarkus-tika` | the JAXP default |

| `camel-quarkus-xmlsecurity` | the JAXP default |

| **Component** | `camel-quarkus-support-xalan` (XSLT support extension) |

| **CWE** | CWE-611 (Improper Restriction of XML External Entity Reference) |

| **Attack vector** | An external entity or external DTD declared in the XML document being transformed, where the body reaches the `xslt` endpoint already as a `javax.xml.transform.Source` |

| **Impact** | Read local files; issue requests to internal network locations (SSRF) |

| **Affected Versions** | From 3.2.0 before 3.33.3, from 3.34.0 before 3.40.0 |

| **Fixed Versions** | 3.33.3 (LTS stream), 3.40.0 |

| **GitHub issue** | [apache/camel-quarkus#9115]( |

| **Credit** | Discovered by internal analysis |

Advisory:

`XalanTransformerFactory` now applies the restrictions itself instead of relying on attributes Xalan cannot

- Documents being transformed are parsed with an `XMLReader` that resolves neither external general nor

external parameter entities and does not load external DTDs — the same configuration Apache Camel's

`XmlConverter.createSAXParserFactory()` uses for the bodies `camel-xslt` converts to a `SAXSource` itself.

A `SAXSource` carrying a caller-configured `XMLReader` is used as it is, and `DOMSource` and `StAXSource`

- Resources fetched at transform time by the `document()` function are denied unless the application's own

`URIResolver` resolves them, and the restriction is installed on every entry point that hands out something

to transform with, including the SAX push entry points whose transformers Xalan does not copy the factory

resolver onto. Applications that set their own resolver — `camel-xslt` does so on every exchange — keep

[`9a570b64`]( and

[`9dd11779`](

[`ad9c5236`]( and

[`3d886769`](

- Do not pass a `javax.xml.transform.Source` built from untrusted input into an `xslt` endpoint. Leave the

message body as `String`, `byte[]` or `InputStream` so that Apache Camel converts it to a `SAXSource` with

- `convertBodyTo` on an existing `Source` body is **not** a workaround: that conversion performs an identity

transform through the same factory. Probe 5 in the reproducer is that identity transform, and it leaks.

- Application or library code that relies on JAXP external access restrictions should request the JDK

implementation explicitly, naming `com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl`,

rather than relying on `TransformerFactory.newInstance()`. Probe 6 is that control, and it denies the read.

This repository is published for educational and defensive purposes: to help Apache Camel Quarkus users

understand the vulnerability, verify whether they are affected, and confirm that upgrading resolves it. Do

not use this material against systems you do not own or operate.