This is an automated email from the ASF dual-hosted git repository.

ppkarwasz pushed a commit to branch feature/threat-model-caller-supplied-parsers
in repository https://gitbox.apache.org/repos/asf/commons-xml.git

commit ea63d0366ecc9ce48ec68e81430a548eed41272d
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Sat Aug 1 18:27:16 2026 +0200

    Treat caller-supplied parser instances as trusted configuration
    
    A recurring report shape builds its own permissively configured
    XMLReader, wraps it in a SAXSource, and reports the resulting entity
    resolution against the library. The code already takes a position on
    this (a SAXSource carrying its own XMLReader is trusted as-is), but the
    threat model never said it, so such a report could only land in
    MODEL-GAP.
    
    State it in the model: parser objects the caller constructs outside the
    library (XMLReader in a SAXSource, StAX readers in a StAXSource, a
    pre-parsed DOMSource) sit on the trusted side of the boundary, like the
    factory configuration. Add the matching out-of-scope bullet with the
    safe alternative (route your reader through XmlFactories.harden), a
    known non-finding describing the report shape, and widen the caller
    input disposition to cover it.
    
    Assisted-By: Claude Fable 5 <[email protected]>
---
 src/site/markdown/threat_model.md | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/site/markdown/threat_model.md 
b/src/site/markdown/threat_model.md
index 985216f..c7e81d1 100644
--- a/src/site/markdown/threat_model.md
+++ b/src/site/markdown/threat_model.md
@@ -63,6 +63,15 @@ process can always reconfigure or replace the factory, so 
such a caller is not a
 defends against: that is the reason reconfiguration moves a report
 [out of scope](#what-is-out-of-scope).
 
+The same holds for parser objects the caller constructs outside the library 
and passes in:
+an `XMLReader` wrapped in a `SAXSource`,
+a StAX reader inside a `StAXSource`,
+or a document parsed elsewhere and handed over as a `DOMSource`
+are **trusted** configuration, not untrusted input.
+The library hardens what it creates;
+it does not re-harden what you built,
+because your reader's settings are indistinguishable from configuration you 
chose deliberately.
+
 ### What is in scope
 
 - The hardening recipes applied by `XmlFactories` to the JAXP implementations 
it recognizes (stock JDK, Apache Xerces,
@@ -184,6 +193,16 @@ and reports against a factory reconfigured in any of the 
ways below are out of s
 - **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.
+- **Caller-supplied parser instances.**
+  A parser built outside `XmlFactories` and handed to a produced instance is 
used as configured:
+  a `SAXSource` carrying its own `XMLReader`,
+  a `StAXSource` carrying a stream or event reader,
+  or a `DOMSource` holding a document parsed elsewhere.
+  Its settings are yours, including permissive ones.
+  To parse with your own reader under the hardening guarantees,
+  route it through `XmlFactories.harden(XMLReader)`
+  (or build it from `XmlFactories.newSAXParserFactory()`)
+  before wrapping it in a `SAXSource`.
 - 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.
 
@@ -207,6 +226,13 @@ are **not** vulnerabilities under this model:
   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 demonstrated on a parser the reporter configured themselves:
+  for example enabling `external-general-entities` on a self-built `XMLReader`,
+  wrapping it in a `SAXSource`,
+  and showing that a produced `Transformer`, `Validator` or `SchemaFactory` 
resolves the entity.
+  The permissive settings belong to the reporter's own reader,
+  not to an instance this library produced
+  (see **Caller-supplied parser instances** under [What is out of 
scope](#what-is-out-of-scope)).
 - 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
@@ -220,7 +246,7 @@ A report judged against this model receives exactly one of:
 | --- | --- |
 | `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: caller input` | The behavior follows from a top-level URI, a 
parser instance the caller constructed outside the library, 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. |
 

Reply via email to