fbeta ePA3-Service-OpenSource
AES-GCM Nonce Reuse via Frozen VAU Request Counter
fbeta's ePA3-Service initialises request_counter but never increments it; every outgoing inner-VAU message header carries request_counter=0. The gematik lib-vau server uses that value for the counter portion of its own AES-GCM IV, reducing IV uniqueness to 32 random bits and exposing the channel to the Joux forbidden attack at ~77,000 responses.
Description
The VAU client initialises two counters at VAUProtokoll.py:64-65: encryption_counter, used for the client's own IV and incremented at line 399, and request_counter, used in the outgoing message header and never incremented anywhere. The gematik specification A_24628-01 requires the client to increment this counter for every request. Andreas Hallof's upstream vau-protokoll (from which fbeta's cryptographic layer is derived) includes the increment; the corresponding fbeta code path does not.
VAUProtokoll.py:64-65
self.encryption_counter = 0self.request_counter = 0VAUProtokoll.py:407 (counter in outgoing header)
header.extend(self.request_counter.to_bytes(8, "big"))The gematik lib-vau server stores the client-supplied counter without monotonicity checks and uses it to construct the counter portion of its own AES-GCM IV, in violation of A_24631 (which requires an independent server-side counter). With the client locked at zero, the server's response IV becomes random(4) || 0x0000000000000000: 32 bits of entropy, with a birthday collision probability reaching 50% at ~77,000 messages. The corresponding lib-vau side is published as the gematik: AES-GCM Nonce Reuse in VAU Server Encryption.
Birthday collision probability for a fixed 64-bit counter:
Collision probability under a fixed counter
Messages P(IV collision) 100 < 0.01 % 1,000 0.01 % 10,000 1.16 % 50,000 25.23 % 77,163 50.00 % 100,000 68.55 %AES-GCM provides no confidentiality or integrity guarantees on nonce reuse. The Joux forbidden attack (2006) lets an attacker who observes two ciphertexts encrypted under the same key and IV recover the GHASH authentication key H from the two authentication tags, and XOR the two ciphertexts to recover plaintext bytes. The inner HTTP responses on the VAU channel have highly predictable structure (HTTP headers, JSON fields, fixed-position KVNR digits), so partial-known-plaintext recovery is feasible without any further attacker capability.
During testing, a transparent proxy observed only encrypted traffic (no MITM, no decryption) and waited for a birthday collision on the 32-bit random IV prefix. After 57,248 encrypted responses two messages shared the same IV; all 9 patient-ID digits differed between the two patients, and the candidate-pair counts per digit position reduced the joint search space by a factor of 60:
Passive nonce collision observed by transparent proxy
11m43s | 55451 unique IVs | prob: 30.1%
COLLISION after 57248 encrypted responses.Response A (#53331): IV = e0cc7a0e 00000000Response B (#57247): IV = e0cc7a0e 00000000
Patient ID digits (bytes 188-196): Pos 0: XOR=0x06 8 candidate pairs Pos 1: XOR=0x07 8 candidate pairs Pos 2: XOR=0x0b 4 candidate pairs Pos 3: XOR=0x04 8 candidate pairs Pos 4: XOR=0x07 8 candidate pairs Pos 5: XOR=0x06 8 candidate pairs Pos 6: XOR=0x0d 4 candidate pairs Pos 7: XOR=0x02 8 candidate pairs Pos 8: XOR=0x0d 4 candidate pairs
9/9 digits differ between the two patients.Search space: 1,000,000,000 -> 16,777,216Reduced by factor 60x from a single collision.A second collision typically narrows the joint candidate set to a unique recovery.
Impact
- The inner-VAU layer protects a patient's medication records, diagnostic reports, prescription history, KVNRs, document reads and writes, and the authorization transactions that control access to the record.
- A passive attacker who observes only encrypted VAU responses on the network path can wait for a birthday IV collision (~77k responses for 50% probability, observed at ~57k during testing) and recover patient-ID digits and other predictable plaintext from the XOR of the two colliding ciphertexts. The precondition is passive network observation; no active intervention is required.
- An attacker who recovers two ciphertexts under the same IV applies the Joux forbidden attack to recover the GHASH authentication key
H. WithH, the attacker forges the GCM authentication tag for ciphertexts under any IV where a collision has been observed, enabling tampering with server-to-client VAU messages: injecting false patient data or fake authorization responses into the channel. - If fbeta: TLS Certificate Verification Universally Disabled is also unmitigated, TLS termination removes the passive-observation prerequisite and the system-level AC collapses to L.
Mitigation
Update fbeta ePA3-Service-OpenSource to 1.3.0 or later. The fix increments request_counter on every outgoing message and validates response counter monotonicity to prevent replay. The same root condition exists upstream in the gematik lib-vau server (which stores the client counter without monotonicity check and uses it as the IV counter portion); see the gematik: AES-GCM Nonce Reuse in VAU Server Encryption. A downstream fix that always sends a fresh counter removes the passive trigger of the server-side condition but does not close the server-side gap against an active MITM who pins a fixed counter at the relay layer.
Defender's Checklist
Update to fbeta ePA3-Service-OpenSource 1.3.0 or later.
All versions before 1.3.0 are affected. The fix lives in pull request #10.
Verify the increment in your build.
In your deployment of the library, run a short integration test that captures two consecutive outgoing VAU messages and asserts that the 8-byte
request_counterfield in the header changes between them. The original gap manifested as a single missing line in the encrypt path; an integration assertion is the cheapest way to keep it from coming back in a fork.Check response counter monotonicity.
The fix also adds monotonicity validation on the response counter. If you maintain a custom client, replace any equality check on the response counter with
response_counter > last_seen_response_counterto prevent replays of past server responses.Treat session length as a security parameter while a fix rolls out.
Until the increment is in place across your fleet, rotate VAU sessions well below the 2^16-message boundary. The IV-collision probability passes 1% around 10,000 same-counter responses; that is your operational margin.
Severity Reasoning
References
- GHSA-vmfm-3f7g-r9qg (fbeta)
- fbeta ePA3-Service-OpenSource PR #10 (fix)
- fbeta ePA3-Service-OpenSource Repository
- gemSpec_Krypt A_24628-01 (Client encryption counter)
- NIST SP 800-38D (AES-GCM)
- Joux (2006), Authentication Failures in NIST version of GCM
- Related upstream: AES-GCM Nonce Reuse in gematik lib-vau
- Related: TLS Certificate Verification Disabled
- Related: ePA-VAU Client Security overview
How We Can Help
Who We Are
The security researchers behind this advisory.

Dr. rer. nat. Simon Weber
Senior Pentester & MedSec Researcher
I evaluate your SaMD with the same industry-defining security insight I contributed to the BAK MV for the revision of the B3S standard.
- PhD on Hospital Cybersecurity
- Critical vulnerabilities found in hospital systems
- Alumni of THB MedSec Research Group
- gematik Security Hero

Dipl.-Inf. Volker Schönefeld
Senior Application Security Expert
As a former CTO and developer turned pentester, I work alongside your team to uncover vulnerabilities and find solutions that fit your architecture.
- 20+ years as CTO, 50M+ app downloads
- Architected and secured large-scale IoT fleets
- Certified Web Exploitation Specialist
- gematik Security Hero
Looking for a Penetration Test?
Machine Spirits specializes in security assessments for medical devices and healthcare IT. From MDR penetration testing to C5 cloud compliance, we help MedTech companies meet regulatory requirements.
