Package org.apache.commons.xml.secure


package org.apache.commons.xml.secure
Apache Commons Secure XML provides secure-by-default JAXP factory creation for Java. A single method call returns a secure JAXP factory that can be used to safely parse XML files.

Every method returns new, secure factory instances. No caching or pooling is performed; callers on a hot path are responsible for their own caching.

A returned factory is not necessarily an instance of the underlying implementation. It might be (and usually is) a wrapper around it, so it cannot be cast to the implementation's own class. Everything else about the implementation's behavior is preserved: features, properties, and attributes delegate to it, and only the security behavior is secure.

Preserved behavior includes the choice of internal parsers. Each TrAX, XPath, or schema implementation has its own way of instantiating them, and the library respects it:

  • Stock JDK factories use the JDK parsers by default, and expose the jdk.xml.overrideDefaultParser feature (and Java system property of the same name) to switch to parsers instantiated through ServiceLoader.
  • Saxon selects its parsers through its own configuration.

Whichever parser is selected, it is secure.

Security Guarantees

Every factory returned by this library makes the same three guarantees, regardless of which JAXP implementation is on the classpath:

  • External DTDs are not fetched.
  • External entities are not resolved.
  • Internal entity expansion is bounded by the platform's secure-processing limit, so DoS payloads such as Billion Laughs are rejected before they exhaust resources.

These guarantees are defined on OpenJDK 8 or later (and JDK distributions built from it). No version of Android supports XMLConstants.FEATURE_SECURE_PROCESSING, so on Android (API level 26 or later) the securing is applied as best-effort without a guarantee, tested as complete starting with API level 33; see the threat model's "Assumptions about the environment".

The guarantees hold whether or not the caller opts into DTD validation (setValidating(true)) or attaches a compiled XSD via setSchema: every external resource the validation would otherwise fetch (the DTD itself, an xsi:schemaLocation hint, an external entity referenced from the DTD) remains blocked.

Each method adds factory-specific guarantees on top of the three above, documented on the corresponding newXxxFactory() method.

Each factory class mirrors every static factory method of its JAXP counterpart:

  • the class-name/class-loader overloads and the StAX newFactory family (JDK 8),
  • newDefaultInstance() (Java 9), and
  • the namespace-aware newNSInstance() family (Java 13).

All of them work, with the same semantics, on every supported runtime, including Java 8. The newDefaultInstance methods are an opt-out of JAXP pluggability: they pin the platform's built-in implementation instead of whatever a classpath lookup would resolve, which suits a library with minimal XML requirements that does not want to delegate the choice of implementation to the application developer. The DOM, SAX and schema variants fall back to the standard lookup where the runtime provides neither the Java 9 method nor the JDK's built-in class (for example, Android, whose own lookup is pinned to the platform parser, and for schemas falls back to exactly the Xerces implementation).

An unresolved external reference resolves to empty content by default, so the parse continues without the resource. To reject it with an exception instead, set the system property org.apache.commons.xml.secure.throwOnUnresolved to true; the property is read at resolution time, and references resolved by a caller-supplied resolver are unaffected.

Caller-supplied URIs

A top-level URI passed directly by the caller is fetched as-is: StreamSource(systemId), DocumentBuilder.parse(String), or a SAXSource built from a system id all cause the JAXP implementation to open that URI without consulting the secure layer. Use a URIResolver or EntityResolver if you need to restrict the top-level fetch.

Thread safety

The returned factories inherit the thread-safety properties of the underlying JAXP implementation, which in practice means they are not guaranteed to be thread-safe. Create a new factory per thread or synchronize externally.