CVE-2026-81876 Overview
CVE-2026-81876 is a denial-of-service vulnerability in HAPI FHIR, the Java implementation of the HL7 FHIR standard for healthcare interoperability. The flaw resides in SHCParser within org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java. When the parser processes attacker-controlled Smart Health Card (SHC) JWT content declaring zip: "DEF" with an empty or truncated raw-DEFLATE payload, the inflation loop fails to terminate. A single malformed validation request can pin a JVM worker thread indefinitely, and concurrent requests can exhaust all validation workers. The issue is fixed in version 6.9.12.
Critical Impact
Unauthenticated network attackers can exhaust FHIR validation worker threads and render the service unavailable by submitting malformed Smart Health Card content.
Affected Products
- HAPI FHIR (org.hl7.fhir.core) versions prior to 6.9.12
- The org.hl7.fhir.r5 module containing SHCParser
- Applications invoking ResourceChecker for file-format detection
Discovery Timeline
- 2026-09-16 - CVE-2026-81876 published to NVD
- 2026-09-17 - Last updated in NVD database
Technical Details for CVE-2026-81876
Vulnerability Analysis
The vulnerability is an infinite loop condition [CWE-20] triggered during Smart Health Card JWT decompression. SHCParser.decodeJWT() calls SHCParser.inflate(), which drives java.util.zip.Inflater in a while (!inflater.finished()) loop. When the DEFLATE payload is empty or truncated, Inflater.inflate() returns zero bytes while Inflater.finished() remains false and Inflater.needsInput() returns true. The loop makes no progress but never exits.
The same zero-progress pattern exists in SHCParser.decompress(), and neither location checks Inflater.needsDictionary() as a termination condition. Because ResourceChecker.java can reach SHC parsing during file-format detection, the vulnerable path is reachable during routine validation rather than only when clients explicitly submit SHC content.
Root Cause
The root cause is missing loop-termination logic around Inflater.inflate(). The implementation assumes non-zero progress on each iteration and does not handle the documented case where the inflater returns zero bytes pending additional input or a preset dictionary. Empty or truncated raw-DEFLATE input satisfies exactly this condition.
Attack Vector
An unauthenticated remote attacker submits a validation request containing a crafted Smart Health Card JWT. The header declares zip: "DEF" while the payload segment contains an empty or truncated raw-DEFLATE stream. The receiving JVM worker thread enters the non-terminating inflate loop and consumes CPU indefinitely. Repeating the request in parallel exhausts the validation worker pool and denies service to legitimate clients.
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(compressed.length)) {
while (!inflater.finished()) {
length = inflater.inflate(buffer);
- outputStream.write(buffer, 0, length);
+ if (length > 0) {
+ outputStream.write(buffer, 0, length);
+ } else {
+ // Handle the 0 byte return condition
+ if (inflater.needsInput()) {
+ // Break out if no more input chunks are available
+ break;
+ }
+ if (inflater.needsDictionary()) {
+ // Break out if a preset dictionary is missing
+ break;
+ }
+ }
}
return outputStream.toString(StandardCharsets.UTF_8.name());
}
Source: GitHub Commit edd5d8c. The patch adds needsInput() and needsDictionary() termination checks when Inflater.inflate() returns zero bytes.
Detection Methods for CVE-2026-81876
Indicators of Compromise
- Validation requests containing JWT payloads with a header field zip: "DEF" and unusually short or empty compressed segments
- FHIR worker threads observed in Inflater.inflate frames for extended periods via thread dumps
- Sustained 100% CPU on one or more JVM threads correlated with /Validate, /$validate, or file-detection endpoints
Detection Strategies
- Monitor validation endpoints for spikes in request duration, request timeouts, and thread-pool saturation
- Periodically capture JVM thread dumps and alert on threads stuck in org.hl7.fhir.r5.elementmodel.SHCParser.inflate or decompress
- Inspect HTTP request bodies for application/smart-health-card content or JWT structures whose header decodes to include "zip":"DEF"
Monitoring Recommendations
- Enable per-request timeout and CPU-accounting metrics on FHIR validation services
- Alert when the worker pool utilization exceeds a defined threshold for longer than the normal validation window
- Correlate 5xx and gateway-timeout responses with source IPs submitting SHC payloads to identify probing activity
How to Mitigate CVE-2026-81876
Immediate Actions Required
- Upgrade org.hl7.fhir.core to version 6.9.12 or later across all deployed HAPI FHIR services
- Inventory applications that transitively depend on org.hl7.fhir.r5 and confirm the resolved version after upgrade
- Enforce per-request wall-clock and CPU timeouts on validation worker threads to bound the impact of any similar future issue
Patch Information
The fix is delivered in org.hl7.fhir.core version 6.9.12 through pull request GitHub Pull Request #2493 and commits d804558 and edd5d8c. See the GitHub Security Advisory GHSA-gq9c-wmrm-5hvr for the full vendor advisory.
Workarounds
- Reject or strip incoming Smart Health Card content at an API gateway or reverse proxy until the upgrade is complete
- Configure request-size limits and reject JWT payloads whose compressed segment falls below a plausible minimum length
- Isolate FHIR validation workloads into a dedicated worker pool so that thread exhaustion does not affect other endpoints
# Maven dependency example - upgrade to the patched release
mvn versions:use-dep-version \
-Dincludes=ca.uhn.hapi.fhir:org.hl7.fhir.r5 \
-DdepVersion=6.9.12 \
-DforceVersion=true
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

