high · 7.5CVE-2026-49485Jul 9, 2026

CVE-2026-49485: org.hl7.fhir.dstu2 FHIRPathEngine ReDoS via Unprotected matches()

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A missed line in the DSTU2 FHIRPath engine means any unauthenticated user can lock a server CPU indefinitely by submitting a FHIR resource that contains a catastrophically backtracking regular…

Packageca.uhn.hapi.fhir:org.hl7.fhir.dstu2
Ecosystemmaven
Affected>= 6.9.5, < 6.9.9
Fixed in6.9.9

The problem

The matches() function in org.hl7.fhir.dstu2/utils/FHIRPathEngine.java (line 2462) calls the raw Java String.matches(sw) with no timeout or complexity guard. This is an incomplete fix: the sibling function replaceMatches() in the same file was correctly updated to use RegexTimeout.replaceAll(), but matches() was skipped.

Any caller of the DSTU2 FHIRPathEngine is exposed, including the FHIR Validator HTTP endpoint and any FHIR server that evaluates user-supplied profiles or invariants. No authentication is required.

Proof of concept

A working proof-of-concept for CVE-2026-49485 in ca.uhn.hapi.fhir:org.hl7.fhir.dstu2, with the exact payload below.

http
POST /validate HTTP/1.1
Host: fhir-server.example.com
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "name": [
    {
      "text": "aaaaaaaaaaaaaaaaaaaaaa!"
    }
  ],
  "_fhirPath": "name.text.matches('(a+)+$')"
}

Java's NFA-based regex engine evaluates (a+)+$ against a string like aaaaaaaaaaaaaaaaaaaaaa! with O(2^n) backtracking. The engine explores every possible grouping of the repeated a+ captures before concluding no match, pinning a CPU core at 100% for the duration.

The root cause is a one-line omission in the patch for CVE-2026-45367. The vulnerable code path is result.add(new BooleanType(convertToString(focus.get(0)).matches(sw))), which has no thread interruption path. The fix replaces this with RegexTimeout.matches(st, sw, regexTimeoutMillis), matching what was already done in DSTU3 and all later modules.

CWE-1333 (Inefficient Regular Expression Complexity) combined with CWE-400 (Uncontrolled Resource Consumption).

The fix

Upgrade ca.uhn.hapi.fhir:org.hl7.fhir.dstu2 (and related modules org.hl7.fhir.convertors, org.hl7.fhir.validation) to version **6.9.10** or later. That release replaces the raw String.matches(sw) call at line 2462 of FHIRPathEngine.java with RegexTimeout.matches(st, sw, regexTimeoutMillis), giving the evaluation thread a bounded timeout.

If an immediate upgrade is not possible, consider fronting the FHIR Validator endpoint with a reverse proxy that enforces request timeouts and rate limits.

Reporter not attributed.

References: [1][2]

Related research