Skip to content

Secure getAssociatedStylesheet, and pin the CI Zulu job to JDK 8u152 - #74

Merged
garydgregory merged 3 commits into
mainfrom
ci/zulu-8u152
Sep 1, 2026
Merged

Secure getAssociatedStylesheet, and pin the CI Zulu job to JDK 8u152#74
garydgregory merged 3 commits into
mainfrom
ci/zulu-8u152

Conversation

@ppkarwasz

@ppkarwasz ppkarwasz commented Sep 1, 2026

Copy link
Copy Markdown
Member

Pushed as a branch on apache/commons-secure-xml rather than from a fork, so the workflow change takes effect on this PR's own run.

getAssociatedStylesheet takes two untrusted inputs — the document it scans, and the href the xml-stylesheet PI names — and each reached an implementation unfiltered. Both are fixed here, and the CI job that makes the first one reproducible is moved at the same time so the change and its coverage land together.

The scan

Apache Xalan provisions its own parser rather than using the one a SAXSource carries (XALANJ-2849), which the wrapper already worked around with a DOM pre-parse. The JDK's XSLTC did exactly the same before 8u162: through 8u152 getAssociatedStylesheet never inspects the source and always builds a parser via FactoryImpl.getSAXFactory, so on Java 8 the document was scanned by a parser this library never configured. With external Xerces on the classpath — where FEATURE_SECURE_PROCESSING bounds expansion but does not restrict external DTD or entity resolution — the prolog's external DTD was fetched outright.

The DOM pre-parse now applies when the delegate is Xalan or the runtime is Java 8. Java 8 as a whole is the boundary rather than 8u162: the patch levels are indistinguishable through any API, and this method is rarely called, so a runtime that old pays a DOM materialisation it will not notice.

The pre-parse also now covers a SAXSource that carries the caller's own reader. That is the one place in this class where a caller-supplied reader is not honoured, and deliberately so: an engine that reaches this path discards that reader regardless, so the choice is only between this parse and the engine's unsecured one. Previously such a source fell through to the implementation, which the class Javadoc wrongly described as safe.

The href

XSLTC-lineage engines resolve the PI href during the scan — before they install the factory's URIResolver (the misplaced "bug 24187" fix) — and return a live SAXSource naming the absolutized URI. Since compiling the returned Source is this method's one documented use, that handed back a URI chosen by the parsed document, to be fetched and executed on the next call.

The result is now routed through the same floor as any other content-named reference: a caller's URIResolver opts an href in, everything else resolves to empty. Saxon already floored the href itself, so this also makes the engines agree.

Behavioural change for callers, documented on SecureTransformerFactory: the returned Source carries empty content rather than naming the URI unless a URIResolver opts that href in. Compiling it therefore compiles the caller's opted-in stylesheet or an empty one — never one the document selected.

CI

The Zulu job existed to cover the oldest JDK 8 behaviour the securing has to work against, but its pin (8u201) already carried the 8u162 backport wave, so it duplicated the other Java 8 jobs. It moves to 8u152, the last release before that wave, which is what makes the scan gap above reproducible in CI at all. jdk.xml.overrideDefaultParser arrived in the same wave, so OverrideDefaultParserTest now probes for the feature and skips where the runtime lacks it, instead of failing 28 times for its absence.

Verification

  • Full surefire matrix green on the current JDK, and on Zulu 8u152 (before these fixes the same 8u152 run failed AssociatedStylesheetTest.secureGetAssociatedStylesheetIgnoresExternalDtd on stockjdk and jdk-xerces).
  • The reproduction that demonstrated the gap — getAssociatedStylesheet on 8u152 with Xerces present, against a prolog declaring an unreachable external DTD — went from ConnectException (fetch attempted) to completing with no fetch.
  • AssociatedStylesheetTest gains an opt-in case and a caller-supplied-reader case; its previous assertion encoded the pre-fix behaviour and was reworked accordingly.
  • javadoc:javadoc clean.

🤖 Generated with Claude Code

The Zulu job exists to cover the oldest JDK 8 behavior the securing has
to work against, but 8u201 already carries the 8u162 backport wave. Pin
it to 8u152, the last release before XSLTC's getAssociatedStylesheet
began honoring the XMLReader carried by a SAXSource: through 8u152 it
self-provisions a parser instead, which the newer job cannot exercise.

jdk.xml.overrideDefaultParser arrived in the same wave, so
OverrideDefaultParserTest now skips where the runtime does not
recognize the feature rather than failing on it.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLnTBsvmYtxzNTWVGNyz33
The PI scan and the href it yields are each derived from the scanned
document, and each reached an implementation unfiltered.

The scan: Apache Xalan provisions its own parser instead of using the
one a SAXSource carries (XALANJ-2849), and the JDK's XSLTC did the same
before 8u162, so on Java 8 the document was scanned by a parser this
library never configured. Pre-parse to a DOM for those engines, keying
on Java 8 as a whole since the patch levels are indistinguishable
through any API. Include a SAXSource that carries the caller's own
reader: an engine that reaches this path drops that reader anyway, so
the choice is only between this parse and the engine's own.

The href: XSLTC-lineage engines resolve it during the scan, before the
factory's URIResolver is installed, and hand back a live Source naming
the absolutized URI, which compiling would then fetch. Route it through
the floor like any other content-named reference, so a caller resolver
opts it in and everything else resolves to empty. Saxon already behaved
this way, so the engines now agree.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLnTBsvmYtxzNTWVGNyz33
@ppkarwasz ppkarwasz changed the title Pin the CI Zulu job to JDK 8u152 Secure getAssociatedStylesheet, and pin the CI Zulu job to JDK 8u152 Sep 1, 2026
@garydgregory
garydgregory merged commit 9192933 into main Sep 1, 2026
16 checks passed
@garydgregory
garydgregory deleted the ci/zulu-8u152 branch September 1, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants