Alle Sicherheitshinweise

OpenReception

Nicht authentifizierte WebAuthn-Passkey-Injection

POST /api/auth/passkeys fügt dem durch eine userId im Request-Body benannten Konto einen WebAuthn-Credential hinzu, ohne authentifizierte Session und ohne WebAuthn-Registrierungszeremonie. Ein Angreifer fügt einem bestätigten Staff-Konto einen selbst kontrollierten Passkey hinzu und meldet sich anschließend als dieses Konto an. Die userId des Kontos ist nicht geheim: Das Mitarbeiterverzeichnis des öffentlichen Buchungsflows gibt sie an jeden nicht authentifizierten Aufrufer zurück. Der zugehörige Endpunkt register/[id] wurde mit CVE-2026-48087 gegen Passkey-Injection gehärtet; diese Änderung greift bei diesem Endpunkt nicht. Alle Releases bis einschließlich 1.1.0 sind betroffen; behoben in 1.1.1.

Verfasst vonVolker Schönefeld, Simon Weber2026-06-04
SchweregradKritischCVSS 9.8CVSS-3.1-VektorAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HCWECWE-306 (Missing Authentication for Critical Function)ProduktOpenReceptionBetroffene VersionenAlle Releases bis einschließlich 1.1.0.Behoben in1.1.1CVEAusstehendGHSAGHSA-g233-m625-m3pc

Beschreibung

OpenReception ist eine selbst gehostete, mandantenweise Terminbuchung für Arztpraxen mit Ende-zu-Ende-Verschlüsselung zwischen Clients und Mitarbeitern. Mitarbeiter und Mandanten-Administratoren authentifizieren sich mit WebAuthn-Passkeys. Wir schätzen die Arbeit des Projekts an einem datenschutzfreundlichen Buchungsdesign und die zügige Behebung durch die Maintainer.

Der Endpunkt zum Hinzufügen eines Passkeys zu einem Konto, POST /api/auth/passkeys, erfordert keine authentifizierte Session und führt keine WebAuthn-Registrierungszeremonie durch. Der Handler liest eine userId und einen Public Key aus dem Request-Body und speichert sie:

src/routes/api/auth/passkeys/+server.ts:98-129

export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
if (!body.userId || !body.passkey) { /* 400 */ }
if (!body.passkey.id || !body.passkey.publicKey) { /* 400 */ }
const counter = WebAuthnService.extractCounterFromCredential(body.passkey);
await UserService.addAdditionalPasskey(body.userId, {
id: body.passkey.id,
userId: body.userId,
publicKey: body.passkey.publicKey,
counter,
deviceName: body.passkey.deviceName || "Unknown Device",
});
};

View source →

Der Handler liest niemals locals.user und verifiziert weder eine vom Server ausgestellte Challenge noch eine Attestation, einen Origin oder eine RP ID. UserService.addAdditionalPasskey speichert den gelieferten Public Key auf dem Zielkonto; die einzige Hürde ist, dass sich das Konto nicht mehr im Zustand INVITED befindet, sodass jedes bestätigte Konto akzeptiert wird.

Die Anfrage erreicht keine Authentifizierungs-Guard. Die API-Middleware weist nicht authentifizierte Anfragen nur für Pfade unter /api/admin ab; bei jeder anderen /api/*-Route wird erwartet, dass der jeweilige Handler die Session selbst prüft, was dieser nicht tut. Die OpenAPI-Annotation des Endpunkts kennzeichnet ihn als authentifizierungspflichtig. Der Handler enthält keine Session-Prüfung.

Beim Login verifiziert POST /api/auth/login die WebAuthn-Assertion gegen den für das Konto gespeicherten Public Key und stellt eine Session aus. Da der gespeicherte Schlüssel der des Angreifers ist, verifiziert dessen Assertion und für das betroffene Konto wird eine vollständige Session ausgestellt.

Die Ziel-userId ist nicht geheim. GET /api/tenants/[id]/appointments/staff-public-keys gibt für jeden Mitarbeiter mit aktiver Krypto { userId, publicKey } zurück, abgesichert nur durch ein Buchungs-Access-Token, das jeder anonyme Besucher über den öffentlichen Buchungs-Bootstrap erzeugt (eine Proof-of-Work-Challenge, deren Token in der Antwort zurückgegeben wird). Ein Angreifer, der die E-Mail-Adresse eines Mitarbeiters kennt, erhält dessen userId, injiziert einen Passkey und meldet sich an.

Der zugehörige Bootstrap-Endpunkt POST /api/auth/register/[id] wurde mit CVE-2026-48087 gegen Passkey-Injection gehärtet. Diese Änderung greift bei /api/auth/passkeys nicht, das das ursprüngliche Injection-Primitiv behält; dieses Advisory behandelt den verbleibenden Endpunkt.

Der nicht authentifizierte Pfad übernimmt ein STAFF-Konto eines Mandanten. Aus einer übernommenen STAFF-Session legt das Mitarbeiterverzeichnis des Mandanten TENANT_ADMIN-Konten mit deren userId und E-Mail offen, sodass dieselbe Injection zum Mandanten-Administrator eskaliert. Ein GLOBAL_ADMIN hat keine Mandantenzuordnung und erscheint in keiner mandantenbezogenen Auflistung, ist über diese Kette also nicht erreichbar.

Eine übernommene Session entschlüsselt für sich genommen keine Klientendaten. OpenReception leitet den Entschlüsselungsschlüssel jedes Mitarbeiters bei der Anmeldung aus dessen Authenticator ab und bindet die gespeicherten Key-Shares an den Credential, mit dem sie registriert wurden; der injizierte Passkey erzeugt daher eine authentifizierte Session, aber nicht das Schlüsselmaterial, das die verschlüsselte Termin-Payload schützt. Offengelegt werden dadurch die Metadaten des Mandanten, personenbezogene Mitarbeiterdaten sowie die Integrität und Verfügbarkeit jedes Termindatensatzes, nicht jedoch die verschlüsselte Klienten-Payload.

Auswirkung

  • Ein entfernter, anonymer Angreifer, der die E-Mail-Adresse eines Mitarbeiters kennt, übernimmt dessen Mitarbeiterkonto und hält eine Session mit dessen Berechtigungen über den Mandanten. Die Ende-zu-Ende-verschlüsselte Termin-Payload (Name, Kontaktdaten und Anliegen des Klienten) bleibt verschlüsselt: Sie wird nur durch einen Schlüssel entsperrt, der bei der Anmeldung aus dem Authenticator des Mitarbeiters abgeleitet wird und den der injizierte Passkey nicht reproduzieren kann. Die Session legt jedoch die Termin-Kalendermetadaten des Mandanten (Datum, Uhrzeit, Channel, Agent, Status), das vollständige Mitarbeiterverzeichnis (Namen, E-Mail-Adressen, Rollen, letzte Anmeldezeiten) sowie gespeicherte Klienten-E-Mail-Hashes offen, zusammen mit einer Abfrage, die bestätigt, ob eine gegebene E-Mail-Adresse zu einem Klienten der Praxis gehört.
  • Innerhalb dieser Session handelt der Angreifer mit den Berechtigungen des Kontos. Eine STAFF-Session kann Termine stornieren, bestätigen, ablehnen, fälschen oder dauerhaft löschen und kann Klienten-PIN-Reset-Token ausstellen, mit denen sich Klientenkonten übernehmen lassen. Die Übernahme eskaliert zudem innerhalb des Mandanten: Eine STAFF-Session zählt TENANT_ADMIN-Konten auf und übernimmt sie auf dieselbe Weise, und ein TENANT_ADMIN kann weitere Administratoren einladen, Mitarbeiter ändern oder entfernen sowie die Mandantenkonfiguration und Channels umschreiben.
  • Termine werden ohne Wiederherstellungsmöglichkeit endgültig gelöscht. Das Entfernen eines Mitarbeiters entfernt auch dessen Tunnel-Key-Shares, sodass die durch diese Shares geschützten verschlüsselten Termindaten für die Praxis dauerhaft nicht mehr entschlüsselbar sind, was eine Datenvernichtung und nicht bloß einen Ausfall darstellt. Betroffen sind die Mitarbeiter der Praxis, deren Konten übernommen werden, sowie ihre Klienten, deren Termin-Metadaten offengelegt und deren Datensätze verändert oder vernichtet werden können; die verschlüsselte Termin-Payload selbst bleibt durch einen per-Credential-Schlüssel geschützt, den der Angreifer nicht ableiten kann.

Abhilfe

Aktualisieren Sie auf OpenReception 1.1.1. Der Fix erfordert eine authentifizierte Session bei POST /api/auth/passkeys, bindet den neuen Credential an den angemeldeten Nutzer und verifiziert vor dem Speichern eine vollständige WebAuthn-Registrierungszeremonie (Server-Challenge, erwarteter Origin und RP ID), entsprechend den Schutzmaßnahmen, die der register/[id]-Flow bereits anwendet. Betreiber, die eine betroffene Version eingesetzt haben, können die Tabelle userPasskey auf Credentials prüfen, die ohne vorausgehende Registrierungs-Challenge hinzugefügt wurden, und betroffene Konten neu registrieren. Nach dem Update durch den Betreiber sollten Mitarbeiter ihre eigenen Passkeys neu registrieren und ihr Konto auf nicht wiedererkannte Passkeys oder aktive Sessions prüfen.

Referenzen

So können wir helfen

Wer wir sind

Die Sicherheitsforscher hinter diesem Sicherheitshinweis.

Dr. Simon Weber Profile

Dr. rer. nat. Simon Weber

Senior Pentester & MedSec-Forscher

Ich evaluiere Ihr SaMD mit derselben branchenprägenden Sicherheitsexpertise, die ich dem BAK MV für die Überarbeitung des B3S-Standards beigetragen habe.

  • Promotion über Krankenhaus-Cybersicherheit
  • Kritische Schwachstellen in Krankenhaussystemen gefunden
  • Alumni der THB MedSec-Forschungsgruppe
  • gematik Security Hero
Volker Schönefeld Profile

Dipl.-Inf. Volker Schönefeld

Senior Application Security Expert

Als ehemaliger CTO und Entwickler, der zum Pentester wurde, arbeite ich mit Ihrem Team zusammen, um Schwachstellen aufzudecken und Lösungen zu finden, die zu Ihrer Architektur passen.

  • 20+ Jahre als CTO, 50+ Mio. App-Downloads
  • Architektur und Absicherung großer IoT-Flotten
  • Certified Web Exploitation Specialist
  • gematik Security Hero

Penetrationstest gesucht?

Machine Spirits ist spezialisiert auf Sicherheitsbewertungen für Medizinprodukte und Gesundheits-IT. Von MDR-Penetrationstests bis C5-Cloud-Compliance helfen wir MedTech-Unternehmen, regulatorische Anforderungen zu erfüllen.