This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/commons-xml.git
The following commit(s) were added to refs/heads/main by this push:
new 2e84a77 Fill in security document
2e84a77 is described below
commit 2e84a77de890ebab6b548c5f04b0236fd04ad6eb
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Jul 4 19:34:43 2026 -0400
Fill in security document
---
SECURITY.md | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 182 insertions(+)
diff --git a/SECURITY.md b/SECURITY.md
index 744d4cd..a292016 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -14,4 +14,186 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+# Security Policy
+
The Apache Commons security page is
[https://commons.apache.org/security.html](https://commons.apache.org/security.html).
+
+This page amends Apache Commons security page.
+
+## Threat Model
+
+This is the threat model for the **0.1.x** release line.
+It is versioned with the library: a report against a released version is
triaged against the model as it stood at that version, not at `HEAD`.
+A finding that breaks something listed under [What is in
scope](#what-is-in-scope) should be reported through the channel above;
+a finding that falls under [What is out of scope](#what-is-out-of-scope) will
be closed citing this section.
+
+### Scope and intended use
+
+This library is a helper for **safely creating JAXP factories**. Each
`XmlFactories.newXxxFactory()` method returns a
+fresh, hardened factory whose parsers reject the common XML attacks (external
entity / DTD resolution, XXE, SSRF through
+external references, and entity-expansion denial of service such as Billion
Laughs). The exact guarantee each factory
+makes is documented in the Javadoc:
+
+https://commons.apache.org/sandbox/commons-xml/apidocs/org/apache/commons/xml/factory/XmlFactories.html
+
+The hardening applies to the factory and to the parsers, readers,
transformers, validators and schemas it produces.
+
+### Adversary model and trust boundary
+
+The adversary is whoever controls the XML an application parses, together with
any external system an XML
+document tries to reach through an entity, DTD, schema, stylesheet, or
XInclude reference. The hardening
+exists to stop that untrusted document from reading local resources, reaching
the network, or exhausting
+memory or CPU.
+
+The trust boundary is the factory as returned by `XmlFactories`. The XML
handed to a parser, reader,
+transformer, validator or schema produced by that factory is **untrusted**;
the configuration of the factory
+is **trusted**, and keeping it as delivered is the caller's responsibility. A
caller running in the same
+process can always reconfigure or replace the factory, so such a caller is not
an adversary this model
+defends against: that is the reason reconfiguration moves a report
+[out of scope](#what-is-out-of-scope).
+
+### What is in scope
+
+- The hardening recipes applied by `XmlFactories` to the JAXP implementations
it recognizes (stock JDK, Apache Xerces,
+ Xalan, Saxon, Woodstox, and Android's Expat/KXmlParser).
+- A factory returned by `XmlFactories`, used as delivered, that fails to
provide a guarantee the Javadoc states it
+ provides.
+
+### Assumptions about the environment
+
+The library does not open network connections, spawn processes, install signal
handlers, or read environment variables
+of its own: each `XmlFactories` method only configures and returns a JAXP
factory, and reads the JDK system properties
+listed below. Which hardening recipe applies depends on the JAXP
implementation present on the classpath.
+
+**System properties that modify behavior**
+
+When a factory or parser is created, the library reads the following JDK
system properties and pins each value on every
+recognized parser, including bundled ones that ignore `jdk.xml.*` on their
own. If a property is unset, the fixed value
+shown applies (matching the JDK 25 secure default), regardless of the JDK in
use. These properties are trusted
+deployment configuration: an operator may set one to tighten (or loosen) a
limit globally, but loosening through one is
+reconfiguration, treated like loosening any other reserved setting (see [What
is out of scope](#what-is-out-of-scope)).
+
+- `jdk.xml.elementAttributeLimit`: `200`
+- `jdk.xml.entityExpansionLimit`: `2500`
+- `jdk.xml.entityReplacementLimit`: `100000`
+- `jdk.xml.maxElementDepth`: `100`
+- `jdk.xml.maxGeneralEntitySizeLimit`: `100000`
+- `jdk.xml.maxOccurLimit`: `5000`
+- `jdk.xml.maxParameterEntitySizeLimit`: `15000`
+- `jdk.xml.maxXMLNameLimit`: `1000`
+- `jdk.xml.totalEntitySizeLimit`: `100000`
+
+**Reserved settings (must not be loosened)**
+
+The library MAY rely on the following features, attributes and properties
staying as configured. They are reserved because
+they govern external resource access, DTD, entity or schema handling, the
installation of a resolver, or processing
+limits; loosening any of them, on the returned factory or on a parser, reader,
transformer, validator or schema it
+produces, breaks the hardening for that instance.
+
+- `com.ctc.wstx.dtdResolver`
+- `com.ctc.wstx.entityResolver`
+- `com.ctc.wstx.undeclaredEntityResolver`
+- `http://apache.org/xml/features/disallow-doctype-decl`
+- `http://apache.org/xml/features/nonvalidating/load-external-dtd`
+- `http://apache.org/xml/properties/internal/entity-resolver`
+- `http://javax.xml.XMLConstants/feature/secure-processing`
+- `http://javax.xml.XMLConstants/property/accessExternalDTD`
+- `http://javax.xml.XMLConstants/property/accessExternalSchema`
+- `http://javax.xml.XMLConstants/property/accessExternalStylesheet`
+- `http://saxon.sf.net/feature/allow-external-functions`
+- `http://saxon.sf.net/feature/allowedProtocols`
+- `http://xml.org/sax/features/external-general-entities`
+- `http://xml.org/sax/features/external-parameter-entities`
+- `javax.xml.stream.isSupportingExternalEntities`
+- `javax.xml.stream.supportDTD`
+- `jdk.xml.overrideDefaultParser`
+- the JDK processing-limit properties listed above
+
+This list is not exhaustive: any other feature, attribute, property or system
property that grants access to an external
+resource, relaxes DTD or entity processing, installs a resolver, or raises a
processing limit is reserved on the same
+terms. Installing a resolver through the typed `set*Resolver` methods, or
through the `DefaultHandler` passed to
+`SAXParser.parse`, has the same effect (see [What is out of
scope](#what-is-out-of-scope)).
+
+**Settings you may modify**
+
+The following are security-relevant but safe to change on a returned factory:
the protection they appear to govern is
+enforced by the reserved settings above, which a caller cannot lift.
+
+- **Validation.** You may turn on DTD or XSD validation, using these methods
and features/properties:
+ - `setSchema(Schema)`,
+ - `setValidating(true)`,
+ - `http://xml.org/sax/features/validation`,
+ - `http://apache.org/xml/features/validation/schema`,
+ - `http://java.sun.com/xml/jaxp/properties/schemaLanguage`,
+ - `http://java.sun.com/xml/jaxp/properties/schemaSource`,
+ - `http://apache.org/xml/properties/schema/external-schemaLocation`,
+ -
`http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation`.
+
+ An external DTD or schema named through any of these is still refused, so
supply the schema yourself (in memory through
+ `setSchema` / `schemaSource`, or by installing a resolver that resolves the
resource and does not return `null`).
+
+- **XInclude.** You may turn on XInclude support, using these methods and
features/properties:
+ - `setXIncludeAware(true)`,
+ - `http://apache.org/xml/features/xinclude`.
+
+ As in the previous case, you need to provide a secure resolver.
+
+### What is out of scope
+
+A returned factory is hardened as delivered; reconfiguring it is a decision to
take over hardening for that instance,
+and reports against a factory reconfigured in any of the ways below are out of
scope.
+
+- **Modifying a reserved setting.** Loosening any feature, attribute or
property reserved under
+ [Assumptions about the environment](#assumptions-about-the-environment).
+- **Installing your own resolver.** Setting an entity, resource or URI
resolver, whether it returns `null` or returns
+ content, replaces the resolution policy the hardening relies on. This
includes the `DefaultHandler` passed to
+ `SAXParser.parse(..., DefaultHandler)`, which the parser installs as its
entity resolver.
+- **Caller-supplied top-level URIs.** A URI passed directly to a parse call
(`DocumentBuilder.parse(String)`,
+ `StreamSource(systemId)`, a `SAXSource` built from a system id) is fetched
as-is by the JAXP implementation without
+ consulting the hardening layer. Restrict it yourself if the URI is untrusted.
+- The behavior of a JAXP implementation that `XmlFactories` does not recognize
(it throws rather than returning an
+ unhardened factory), and any defect in the underlying JAXP implementation
itself.
+
+### Downstream responsibility
+
+Use the factory as returned. If you reconfigure it, you take over hardening
for that instance and are responsible for
+re-establishing any protection you remove.
+
+### Known non-findings
+
+XML-security scanners and static analyzers routinely flag the parsers this
library produces. The following
+are **not** vulnerabilities under this model:
+
+- A claim that a factory or instance produced by `XmlFactories` is unsafe,
without showing that a reserved
+ setting was loosened, a resolver was installed, or an untrusted top-level
URI was passed (see
+ [Assumptions about the environment](#assumptions-about-the-environment) and
+ [What is out of scope](#what-is-out-of-scope)). As delivered, the instance
is hardened; the bare presence
+ of a `SAXParser`, `DocumentBuilder`, `XMLReader`, `Transformer`, `Validator`
or `Schema` is not a finding.
+- XXE, external-entity, SSRF-through-external-reference, or entity-expansion
(Billion Laughs) reports against
+ a factory used as delivered. Blocking these is exactly what the hardening
does. A working proof against an
+ unmodified instance is a `VALID` finding (see below); a scanner that
pattern-matches on parser type is not.
+- Reports against an instance after the caller installed a resolver (including
the `DefaultHandler` passed to
+ `SAXParser.parse(..., DefaultHandler)`) or loosened a reserved setting.
+- Reports about a top-level URI the caller passed directly to a parse call.
That URI is fetched as-is and is
+ the caller's to validate.
+- Reports in a JAXP implementation this library does not recognize:
`XmlFactories` throws rather than
+ returning an unhardened factory, so there is no instance to attack.
+
+### Triage dispositions
+
+A report judged against this model receives exactly one of:
+
+| Disposition | Meaning |
+| --- | --- |
+| `VALID` | A factory or instance used as delivered fails to provide a
guarantee its Javadoc states (for example, a hardened parser still resolves an
external entity, or a documented processing limit is not applied). |
+| `OUT-OF-SCOPE: reconfigured` | A reserved setting was loosened, or a
resolver was installed, on the factory or a produced instance before the
reported behavior (see [What is out of scope](#what-is-out-of-scope)). |
+| `OUT-OF-SCOPE: caller input` | The behavior follows from a top-level URI, or
other input, the caller passed directly to a parse call. |
+| `OUT-OF-SCOPE: foreign implementation` | The behavior is in a JAXP
implementation `XmlFactories` does not recognize, or in the underlying JAXP
implementation itself. |
+| `MODEL-GAP` | The report fits none of the above. The model is then
incomplete: revise it rather than making an ad-hoc call. |
+
+### Conditions that would change this model
+
+Revise this model when any of the following change: a new `XmlFactories`
factory method or other public
+surface; support for a JAXP implementation beyond those listed under [What is
in scope](#what-is-in-scope);
+a change in the pinned processing-limit defaults this list records; a new
reserved setting; or a
+report that cannot be routed to one of the dispositions above.