Base SchemaFactory hardening on feature support

Replace the per-implementation class-name dispatch for Schema with a single
wrapper-based recipe, the same for every implementation. The hardening lives
entirely in the existing HardeningSchemaFactory / HardeningSchema /
HardeningValidator wrappers, so there is no per-implementation branching, no
FEATURE_SECURE_PROCESSING and no limit configuration on the factory itself:

- HardeningSchemaFactory installs a deny-all LSResourceResolver on the factory
  (blocking xs:import/include/redefine at compile time) and rewrites every
  newSchema(Source[]) through an XmlFactories-hardened reader.
- HardeningSchema wraps every Validator/ValidatorHandler the inner Schema
  produces and re-installs the deny-all resolver on each (blocking
  xsi:schemaLocation at validation time), since neither the JDK nor Xerces
  reliably propagates it through Schema.
- HardeningValidator rewrites the Source on every validate(Source) call.

The hardened reader from XmlFactories.harden(Source) already carries
FEATURE_SECURE_PROCESSING and the processing limits, so a DOCTYPE, external
entity or Billion Laughs payload in the schema or instance document is bounded
there rather than on this factory.

The JAXP 1.5 ACCESS_EXTERNAL_* properties are deliberately not set: the deny-all
resolver already blocks the same fetches on every implementation, and the JDK 8
SchemaFactory has a bug whereby those properties keep blocking even when a
caller's own resolver would grant the access, so leaving them unset lets a
caller re-enable specific lookups by swapping the resolver. The JDK block now
surfaces as the resolver's SecurityException rather than a SAXException, which
the attack-test assertions already accept.

StockJdkProvider.configure(SchemaFactory), XercesProvider.configure(SchemaFactory)
with its per-product hardeners, XmlFactories.dispatch(SchemaFactory) and
Limits.applyToJdkSchema are removed; XmlFactories.newSchemaFactory() wraps in
HardeningSchemaFactory directly. An implementation is no longer rejected for
being unrecognized.

Assisted-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7 files changed
tree: 70de49b1e4886ecaebcb8e93cd5ada442d0ab87e
  1. .github/
  2. android-tests/
  3. src/
  4. .asf.yaml
  5. .gitattributes
  6. .gitignore
  7. AGENTS.md
  8. CODE_OF_CONDUCT.md
  9. CONTRIBUTING.md
  10. LICENSE.txt
  11. NOTICE.txt
  12. pom.xml
  13. README.md
  14. RELEASE-NOTES.txt
  15. SECURITY.md
README.md

Apache Commons XML

Java CI Maven Central Javadocs CodeQL OpenSSF Scorecard

Apache Commons XML provides secure-by-default JAXP factory creation, abstracting over implementation-specific XXE hardening differences between the stock JDK and external JAXP implementations (Android, Apache Xalan, Apache Xerces, Woodstox, Saxon-HE).

Documentation

More information can be found on the Apache Commons XML homepage. The Javadoc can be browsed. Questions related to the usage of Apache Commons XML should be posted to the user mailing list.

Getting the latest release

You can download source and binaries from our download page.

Alternatively, you can pull it from the central Maven repositories:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-xml</artifactId>
  <version>0.1.0</version>
</dependency>

Building

Building requires a Java JDK and Apache Maven. The required Java version is found in the pom.xml as the maven.compiler.source property.

From a command shell, run mvn without arguments to invoke the default Maven goal to run all tests and checks.

Contributing

We accept Pull Requests via GitHub. The developer mailing list is the main channel of communication for contributors. There are some guidelines which will make applying PRs easier for us:

  • No tabs! Please use spaces for indentation.
  • Respect the existing code style for each file.
  • Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
  • Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running mvn.
  • Before you push a PR, run mvn (without arguments). This runs the default goal which contains all build checks.
  • To see the code coverage report, regardless of coverage failures, run mvn clean site -Dcommons.jacoco.haltOnFailure=false -Pjacoco

If you plan to contribute on a regular basis, please consider filing a contributor license agreement. You can learn more about contributing via GitHub in our contribution guidelines.

License

This code is licensed under the Apache License v2.

See the NOTICE.txt file for required notices and attributions.

Donating

You like Apache Commons XML? Then donate back to the ASF to support development.

Additional Resources

Apache Commons Components