Harden XML parsing via commons-secure-xml - #393
Merged
Merged
Conversation
Create XML stream readers, parsers, schema factories and transformers through org.apache.commons:commons-secure-xml. The secure factories enable FEATURE_SECURE_PROCESSING and install a non-removable entity-resolver floor on every parser they produce: external DTD, entity, schema and XInclude lookups that a caller-set resolver does not resolve are resolved to empty content instead of being fetched, and internal entity expansion is bounded, regardless of the JAXP implementation on the classpath. Changes: - Add the commons-secure-xml dependency (1.0.0-SNAPSHOT until its first release). - Route factory creation through SecureXMLInputFactory, SecureSchemaFactory and SecureDocumentBuilderFactory in SCXMLReader, and through SecureTransformerFactory in SCXMLWriter and ContentParser. A Configuration-supplied XMLResolver still takes precedence: the floor only handles lookups the resolver leaves unresolved, and the factoryId/factoryClassLoader override still selects the underlying implementation. - ContentParser.parseXml now wraps its argument in an InputSource: DocumentBuilder.parse(String) interprets its argument as a URI, so the method never actually parsed the XML content it was documented to parse. - Run the CI and CodeQL builds with -Puse-apache-snapshots (inherited from the org.apache:apache parent POM) so the commons-secure-xml SNAPSHOT resolves; CodeQL's autobuild receives the profile through MAVEN_ARGS. Assisted-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHgnMnGWHQoH2zD2jFdoMT
ppkarwasz
force-pushed
the
feat/use-commons-xml
branch
from
August 31, 2026 15:07
bb35dc4 to
cb9672c
Compare
Bump org.apache.commons:commons-secure-xml from 1.0.0-SNAPSHOT to 1.0.0 and add the temporary staging repository https://repository.apache.org/content/repositories/orgapachecommons-1962/ after Central, so the vote gets downstream CI results. Drop the -Puse-apache-snapshots profile from the CI workflows, which the release version no longer needs. Remove the staging repository once 1.0.0 is released. Assisted-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167e29ScPEdfzJnEFm95imK
garydgregory
reviewed
Sep 6, 2026
Member
|
Hi @ppkarwasz |
SCXMLWriter.getTransformer() logged the failure and returned null, so the static XFORMER field silently became null and every writeNode() call failed later with a NullPointerException far from the actual cause. Throw an IllegalStateException instead, with a message that names the reason: either the TrAX implementation found on the class path rejects the output properties the writer needs, or no implementation could be instantiated at all. Catch IllegalArgumentException from setOutputProperties() as well, and keep TransformerFactoryConfigurationError in the catch so a missing implementation is reported through the same message rather than as a bare Error from the class initializer. The failure can only be caused by the TrAX implementation in use, so there is nothing for a caller to recover from. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0127cAFjN5DYE8pLAysQps4f
getReader() always called SecureXMLInputFactory.newInstance() and then discarded the result when the Configuration supplied a factoryId and a class loader, replacing it with the factory created by newFactory(). Create only the factory that is actually used, and make the local final. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0127cAFjN5DYE8pLAysQps4f
The class had no coverage for its XML methods. Assert that parseXml() treats its argument as an XML document rather than as a URI, which is what DocumentBuilder.parse(String) did before the method started wrapping the string in an InputSource, and that parseContent() maps an XML document to a NodeValue and toXml() round trips back into it. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0127cAFjN5DYE8pLAysQps4f
ppkarwasz
marked this pull request as ready for review
September 11, 2026 08:25
Member
Author
|
This should be correct now. In #394 I fixed the test failure on JDK 27-ea. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Creates XML stream readers, parsers, schema factories and transformers through
org.apache.commons:commons-secure-xml(1.0.0-SNAPSHOT until its first release). The secure factories enable XML secure processing and install a non-removable entity-resolver floor: external DTD, entity, schema and XInclude lookups that a caller-set resolver does not resolve are resolved to empty content instead of being fetched, and internal entity expansion is bounded.SCXMLReadergoes throughSecureXMLInputFactory(theConfiguration-suppliedXMLResolverstill takes precedence, and thefactoryId/factoryClassLoaderoverride still selects the underlying implementation), plusSecureSchemaFactoryandSecureDocumentBuilderFactory;SCXMLWriterandContentParsergo throughSecureTransformerFactory.ContentParser.parseXmlnow wraps its argument in anInputSource:DocumentBuilder.parse(String)interprets its argument as a URI, so the method never actually parsed the XML content it was documented to parse.-Puse-apache-snapshotsso the SNAPSHOT dependency resolves.🤖 Generated with Claude Code