VYPR
High severity7.5NVD Advisory· Published Jun 17, 2026

HAPI FHIR: Incomplete fix for CVE-2026-45367: DSTU2 FHIRPathEngine.matches() missing RegexTimeout protection allows ReDoS

CVE-2026-55470

Description

Summary

The fix for CVE-2026-45367 added RegexTimeout protection to the matches() function in DSTU2016MAY, DSTU3, R4, R4B, and R5, but the DSTU2 module was incompletely patched. In org.hl7.fhir.dstu2, replaceMatches() was updated while matches() at line 2462 still calls the raw String.matches(sw) without any timeout, allowing an unauthenticated attacker to trigger catastrophic regex backtracking and exhaust server CPU.

Details

Incomplete patch

Within the same file (org.hl7.fhir.dstu2/utils/FHIRPathEngine.java), the two functions were patched inconsistently:

Line 2226 — replaceMatches() — PATCHED: ``java result.add(new StringType( RegexTimeout.replaceAll( convertToString(focus.get(0)), regex, repl, regexTimeoutMillis))); ``

Line 2462 — matches() — NOT PATCHED: ``java result.add(new BooleanType( convertToString(focus.get(0)).matches(sw))); // ↑ raw String.matches() — no RegexTimeout, no complexity check ``

DSTU3 line 2447 — matches() — PATCHED (for comparison): ``java result.add(new BooleanType( RegexTimeout.matches(st, sw, regexTimeoutMillis))); ``

Module-by-module status

| Module | matches() | replaceMatches() | |---|---|---| | DSTU2 | ❌ raw str.matches(sw) | ✅ RegexTimeout.replaceAll() | | DSTU2016MAY | ✅ RegexTimeout.matches() | ✅ | | DSTU3 | ✅ RegexTimeout.matches() | ✅ | | R4 | ✅ RegexTimeout.matches() | ✅ | | R4B | ✅ RegexTimeout.matches() | ✅ | | R5 | ✅ RegexTimeout.matches() | ✅ |

PoC

Requirements: Java 17+, Maven 3.8+

pom.xml dependencies: ``xml ca.uhn.hapi.fhir org.hl7.fhir.utilities 6.9.7 ``

Test code (reproduces the exact behaviour of DSTU2 line 2462): ``java import org.hl7.fhir.utilities.regex.RegexTimeout; import java.util.concurrent.*; String regex = "((a|b){0,5}){20}"; String input = "a".repeat(25) + "c"; // no match → full backtracking // ① Patched approach — RegexTimeout terminates at 500 ms long t1 = System.currentTimeMillis(); try { RegexTimeout.matches(input, regex, 500); } catch (TimeoutException e) { System.out.println("RegexTimeout blocked in " + (System.currentTimeMillis() - t1) + " ms"); } // ② DSTU2 line 2462 — raw String.matches(), no timeout long t2 = System.currentTimeMillis(); input.matches(regex); // equivalent to what FHIRPathEngine does System.out.println("str.matches() ran for " + (System.currentTimeMillis() - t2) + " ms with no timeout"); ``

Verified output (JDK 25.0.3, Linux): `` RegexTimeout blocked in 508 ms ← patched modules: attack stopped str.matches() ran for 1410 ms ← DSTU2: no timeout, CPU exhausted ``

The patched approach cuts off the evaluation at 508 ms. The unpatched DSTU2 code runs for 1410 ms on this input with no mechanism to stop it. Longer inputs or more complex patterns produce proportionally worse results.

Impact

Vulnerability type: Regular Expression Denial of Service (ReDoS) causing CPU exhaustion and service disruption.

Who is impacted: Any application using the ca.uhn.hapi.fhir:org.hl7.fhir.dstu2 module that evaluates user-supplied FHIRPath expressions — including the FHIR Validator HTTP endpoint, FHIR servers applying FHIRPath invariants from user-provided resources or profiles, and any system embedding FHIRPathEngine from the DSTU2 module. No authentication is required; an attacker needs only to submit a FHIR resource or FHIRPath expression whose matches() argument contains a catastrophically backtracking regular expression.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Affected products

5

Patches

Vulnerability mechanics

Root cause

"The DSTU2 module's `matches()` function calls Java's raw `String.matches()` without any `RegexTimeout` protection, leaving it vulnerable to catastrophic regex backtracking."

Attack vector

An unauthenticated attacker submits a FHIR resource or FHIRPath expression whose `matches()` argument contains a catastrophically backtracking regular expression (e.g., `((a|b){0,5}){20}`). When the DSTU2 `FHIRPathEngine` evaluates this expression, it calls Java's raw `String.matches()` which has no timeout or complexity check, causing catastrophic backtracking that exhausts server CPU. No authentication is required; the attack can be delivered through any endpoint that evaluates user-supplied FHIRPath expressions, such as the FHIR Validator HTTP endpoint or FHIR servers applying FHIRPath invariants from user-provided resources or profiles. [CWE-1333] [ref_id=1]

Affected code

The vulnerability resides in `org.hl7.fhir.dstu2/utils/FHIRPathEngine.java`. The `matches()` function at line 2462 calls `convertToString(focus.get(0)).matches(sw)` — raw `String.matches()` — without any `RegexTimeout` protection, while the sibling `replaceMatches()` function at line 2226 was correctly patched to use `RegexTimeout.replaceAll()`. All other FHIR modules (DSTU2016MAY, DSTU3, R4, R4B, R5) had both functions patched consistently. [ref_id=1] [ref_id=2]

What the fix does

The patch must replace the raw `String.matches(sw)` call at line 2462 of `org.hl7.fhir.dstu2/utils/FHIRPathEngine.java` with `RegexTimeout.matches(convertToString(focus.get(0)), sw, regexTimeoutMillis)`, mirroring the pattern already applied to `replaceMatches()` in the same file and to `matches()` in all other FHIR modules. This wraps the regex evaluation with a configurable timeout (default 500 ms) that throws a `TimeoutException` when catastrophic backtracking exceeds the limit, preventing CPU exhaustion. [ref_id=1] [ref_id=2]

Preconditions

  • configThe target application must use the `ca.uhn.hapi.fhir:org.hl7.fhir.dstu2` module and evaluate user-supplied FHIRPath expressions via `FHIRPathEngine`.
  • inputThe attacker must be able to submit a FHIR resource or FHIRPath expression containing a catastrophically backtracking regular expression to the `matches()` function.
  • authNo authentication is required; the attack can be delivered over the network to any exposed endpoint that processes FHIRPath expressions.
  • networkThe attacker must have network access to the vulnerable endpoint.

Reproduction

The bundle includes a public PoC. Using Java 17+ and Maven 3.8+, add the dependency `ca.uhn.hapi.fhir:org.hl7.fhir.utilities:6.9.7`. Execute the provided test code: `String regex = "((a|b){0,5}){20}"; String input = "a".repeat(25) + "c"; input.matches(regex);`. The patched `RegexTimeout.matches()` terminates in ~508 ms, while the unpatched `String.matches()` runs for ~1410 ms with no timeout. [ref_id=1] [ref_id=2]

Generated on Jun 17, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.