Skip to content

Prevent XXE in the HL7 v2.x strict parser - #408

Open
pacmano1 wants to merge 1 commit into
OpenIntegrationEngine:mainfrom
pacmano1:fix/hl7v2-strict-parser-xxe
Open

Prevent XXE in the HL7 v2.x strict parser#408
pacmano1 wants to merge 1 commit into
OpenIntegrationEngine:mainfrom
pacmano1:fix/hl7v2-strict-parser-xxe

Conversation

@pacmano1

@pacmano1 pacmano1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

The HL7 v2.x strict parser hands XML-encoded inbound messages to the bundled HAPI 2.3, whose XMLUtils.parse resolves external XML entities with no hardening. On a channel with Use Strict Parser + Validate in Strict Parser, an unauthenticated message to the MLLP/TCP listener could trigger SSRF (internal services, cloud metadata) and local file disclosure. Reported as oie-1; also independently reported by Samuel Paschuan.

Fix

ER7Serializer.CustomDefaultXMLParser.parseStringIntoDocument — the sole path from OIE to the vulnerable parser — is overridden to reject DOCTYPE declarations, matching the disallow-doctype-decl hardening already used on the sibling fromXML path (and ~20 other XML parse sites in the tree).

This is a minimal, non-breaking change. The format the strict parser handles — the official HL7 v2.xml encoding (urn:hl7-org:v2xml) — is defined by XML Schema, not DTDs, so a standards-conformant message does not use a DOCTYPE and is unaffected. (This is distinct from Mirth's own non-strict <HL7Message> format, which is a separate code path the override does not touch, and which is already DOCTYPE-hardened on the fromXML side.) Any inbound message that does carry a DOCTYPE is now rejected rather than parsed — that is the intended hardening, since at the parser level a DOCTYPE-bearing message is indistinguishable from the attack. Existing channels need no changes: no new options, no migration, no configuration.

How this was verified

  • Confirmed the vulnerability at the bytecode level. Disassembled hapi-base-2.3.jar: XMLUtils sets no doctype or external-entity restrictions.
  • Confirmed the fix is comprehensive at a single chokepoint. parseStringIntoDocument is the only caller of XMLUtils.parse across all HAPI parser classes, and both of OIE's parser instances (serialization + deserialization) are the overridden CustomDefaultXMLParser — it is the only HAPI XML parser instantiated in the server/donkey tree.
  • Live MLLP before/after (the authoritative proof). Imported the xxe-poc channel (MLLP :6661, strict + strict validation), sent the report's payload against an out-of-band HTTP catcher:
    • Unpatched build: the catcher logged the callback — SSRF fired, unauthenticated.
    • Patched build: DOCTYPE is disallowed — the message is rejected and the server never calls out.

Tests

Unit tests fire the report's payload on the strict toXML path and assert the parse is rejected with a DOCTYPE-disallowed root cause, alongside a benign v2.xml message that still round-trips (the hardening does not break valid XML).

Honest caveat: the DOCTYPE-rejection unit test asserts the intended behavior but does not by itself discriminate patched from unpatched, because the test-JVM's default XML parser rejects a DOCTYPE regardless — the engine runtime is where HAPI resolves a different, vulnerable parser. The discriminating before/after evidence is the live MLLP reproduction above.

Follow-ups (separate)

  • HAPI upgrade — the hapi-structures 2.3 → 2.6.0 bump is tracked by Renovate in the Dependency Dashboard (Dependency Dashboard #386); the vendored hapi-base jar needs replacing alongside it. This override should stay even after the upgrade: HAPI's 2.4+ fix leaves disallow-doctype-decl=false (permits a DOCTYPE, only disables entity resolution), so this refusal is the stronger posture.
  • Optional surface reduction — an "Allow XML" data type toggle to let a strict HL7 channel refuse XML input entirely (mgaffigan's Prevent XML xxe on Strict HL7 parsing #406) is a separate enhancement, not a security control, and is deliberately out of scope here.
  • A distinct XXE in the generic XML data type's batch adaptor (XMLBatchAdaptor parses inbound content with an unhardened XPathFactory) was found during this work and will be filed and fixed separately.

Credits

Thanks to Samuel Paschuan for reporting the issue, and to Michael Gaffigan (@mgaffigan) and Tony Germano for the design discussion.

The strict parser hands XML-encoded inbound messages to HAPI 2.3, whose
XMLUtils.parse resolves external XML entities. On a channel with the strict
parser and strict validation enabled, an unauthenticated message to the MLLP/TCP
listener could trigger SSRF and local file disclosure.

Override CustomDefaultXMLParser.parseStringIntoDocument -- the sole path to the
vulnerable parse -- to reject DOCTYPE declarations, matching the
disallow-doctype-decl hardening already used on the fromXML path. Legitimate HL7
v2.xml is schema-based and never carries a DOCTYPE, so no valid message is
affected and the strict parser keeps accepting XML as before.

Verified with a live MLLP reproduction (xxe-poc): the unpatched build fetched the
attacker URL; the patched build rejects the message and never calls out.

Signed-off-by: Finnegan's Owner <44065187+pacmano1@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Test Results

677 tests   677 ✅  2m 22s ⏱️
114 suites    0 💤
114 files      0 ❌

Results for commit fefe2ea.

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