Skip to content

Harden XsltTransformer against XXE in the transformed document - #1537

Open
Nexory wants to merge 2 commits into
apache:masterfrom
Nexory:hardening/xslttransformer-xxe
Open

Harden XsltTransformer against XXE in the transformed document#1537
Nexory wants to merge 2 commits into
apache:masterfrom
Nexory:hardening/xslttransformer-xxe

Conversation

@Nexory

@Nexory Nexory commented Aug 7, 2026

Copy link
Copy Markdown

What

XsltTransformer.transform() builds its TransformerFactory with a plain
TransformerFactory.newInstance() and then transforms the decorated
component's rendered output as the XML source document. That source is
attacker-influenceable (it is whatever the component rendered, including user
model data), so an external entity in it is resolved: a crafted document can
read local files or reach internal URLs (XXE).

XSLTResourceStream (wicket-util) already hardens its factory with
FEATURE_SECURE_PROCESSING (PR #862), but the other XSLT entry point,
XsltTransformer, was left untouched. A grep for FEATURE_SECURE_PROCESSING
returns only that one site.

Fix

Enable FEATURE_SECURE_PROCESSING on the factory, mirroring
XSLTResourceStream. On the JDK this also denies external DTD and stylesheet
access, so the external entity is rejected instead of resolved. No change for
legitimate stylesheet transforms.

Verification

  • Standalone under JDK 21: with a plain factory an external general entity in
    the source document leaks a local file's contents into the transform output;
    with FEATURE_SECURE_PROCESSING set the parse is rejected (the
    accessExternalDTD restriction denies the file access).
  • The existing OutputTransformerContainer and transformer tests still pass,
    so legitimate stylesheet transforms are unaffected.

This is defense-in-depth hardening, mirroring the existing XSLTResourceStream
change.

Nexory added 2 commits August 7, 2026 13:48
XsltTransformer.transform() built its TransformerFactory with a plain
TransformerFactory.newInstance() and then transformed the component's rendered
output as the XML source document. That source is attacker-influenceable (it is
whatever the decorated component rendered, including user model data), so an
external entity in it was resolved: a crafted document could read local files
or reach internal URLs.

Enable FEATURE_SECURE_PROCESSING on the factory, mirroring what
XSLTResourceStream already does; on the JDK this also denies external DTD and
stylesheet access, so the external entity is rejected instead of resolved.
Legitimate stylesheet transforms are unaffected (the existing
OutputTransformerContainer tests still pass).
Confirms that an external general entity in the transformed source document is
not resolved. Reuses the identity anyName.xsl stylesheet from the
outputTransformer tests; the test fails (the secret leaks into the output)
without the FEATURE_SECURE_PROCESSING guard.
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.

1 participant