Ein 16 Jahre alter Bug in der Datenbank, die auf Milliarden Mobilgeräten läuft

DatenbankSQLiteInfrastruktur

Quellen:HN + web research · HN

Ein 16 Jahre alter Bug in der Datenbank, die auf Milliarden Mobilgeräten läuft

Im August 2026 veröffentlichte das Netzwerksicherheitsunternehmen Tailscale einen Aufarbeitungsbericht (Postmortem): Die eigene Kern-Datenbank war im vergangenen halben Jahr ohne ersichtlichen Grund 19-mal beschädigt worden. Jedes Mal fiel bei einem Teil der Nutzer das Netzwerk kurzzeitig aus; die Wiederherstellung dauerte oft über eine Stunde. Nach monatelanger Spurensuche stießen die Ingenieure auf die Ursache: einen Bug in der meistinstallierten Datenbanksoftware der Welt, der dort seit mindestens 16 Jahren unbemerkt schlummerte.

Tailscale entwickelt Software, die mehrere Computer sicher zu einem privaten Netzwerk verbindet. Auch wer das Unternehmen nicht kennt, sollte diese Geschichte lesen – denn die betroffene Hauptkomponente läuft jeden Tag auf Ihrem Smartphone.

Eine Software, die jeder nutzt, aber kaum jemand kennt

Zunächst zum Hauptdarsteller: SQLite ist die am weitesten verbreitete Datenbank der Welt. Laut offiziellen Angaben läuft sie auf Milliarden von Geräten. Ob Messengerdienste, Banking-Apps, Webbrowser oder Spiele – fast jede mobile Anwendung nutzt SQLite zur Datenspeicherung.

Das Besondere an SQLite ist seine Eigenschaft als „eingebettete“ Datenbank (Embedded Database). Während große Unternehmensdatenbanken wie ein Banktresor funktionieren, der eigene Wächter und ein separates Gebäude (dedizierte Server) benötigt, ist SQLite wie ein kleiner, tragbarer Safe, den jede App direkt bei sich führt. Keine Installation, keine Serverwartung – einmal integriert, speichern Entwickler Daten darin und müssen sich jahrzehntelang um nichts kümmern.

Diese Einfachheit machte SQLite zum unsichtbaren Fundament der digitalen Welt. Weil Milliarden von Geräten ständig darauf zugreifen, wurde die Zuverlässigkeit unzählige Male auf die Probe gestellt. Fehler wurden auf extrem seltene Wahrscheinlichkeiten reduziert – so selten, dass selbst der Entwickler der Software davon ausging, dass bestimmte Kernpfade fehlerfrei seien.

Ein Riss im Fundament

Seit 2022 speicherte Tailscale seine gesamten Kerndaten in SQLite – eben weil es als „zuverlässig und bewährt“ galt, in der Fachsprache als „langweilige Technologie“ (Boring Technology) bezeichnet. „Langweilig“ ist hier ein Lob: Es bedeutet, dass nichts unvorhergesehenes passiert. Von Anfang 2023 bis Sommer 2025 lief auch alles reibungslos.

Doch im August 2025 meldete die automatisierte Sicherung plötzlich einen Fehler: Eine Datenbankdatei war beschädigt. Das Team reparierte die Datei und untersuchte die Ursache, fand jedoch keine Erklärung. Dann folgte der zweite Vorfall, der dritte… insgesamt 19 Beschädigungen innerhalb von sechs Monaten. In der Systemarchitektur gilt: Wenn die Wahrscheinlichkeit eines Einzelfehlers auch noch so gering ist, wird das unbestimmte seltene Ereignis bei ausreichend großem Volumen und hoher Transaktionszahl zwangsläufig zur Routine.

Besonders tückisch war, dass die 19 Vorfälle keinerlei Gemeinsamkeiten aufwiesen: Es betraf nicht dieselben Server, nicht dieselben Nutzergruppen, keine bestimmten Uhrzeiten und keine identischen Lastmuster. Den Ingenieuren fehlte jeder Anhaltspunkt; der Fehler ließ sich im Labor schlicht nicht reproduzieren.

„Erst Notizzettel, dann Hauptbuch“: Der WAL-Modus

Um die spätere Spurensuche zu verstehen, muss man einen speziellen Betriebsmodus von SQLite kennen: den WAL-Modus (Write-Ahead Log, sinngemäß „Vorab-Schreiblog“).

Stellen Sie sich ein Geschäftshauptbuch vor. Im Standardmodus wird jede neue Transaktion sofort direkt in das gebundene Hauptbuch eingetragen. Im WAL-Modus dagegen werden neue Einträge erst einmal schnell auf einen Stapel Notizzettel geschrieben. Erst wenn sich genügend Zettel angesammelt haben, werden sie gebündelt ins Hauptbuch übertragen. Die Notizzettel entsprechen der WAL-Datei, das Hauptbuch der eigentlichen Datenbankdatei. Der Vorgang des Übertragens heißt in der Fachsprache Checkpoint.

WAL und Datenbankdatei

Abb.: Neue Daten werden zuerst in die WAL-Datei geschrieben und später in die Hauptdatenbankdatei übertragen. Quelle: tailscale.com

Die Vorteile liegen auf der Hand: Das Beschreiben eines Notizzettels geht viel schneller als das Durchsuchen eines schweren Hauptbuchs. Zudem kann das Übertragen in ruhigen Minuten asynchron erfolgen, während Leser ungestört im Hauptbuch blättern können. Viele leistungsorientierte Anwendungen nutzen diesen Modus. Tailscale ging jedoch noch einen Schritt weiter: Um Backups zu erleichtern, lösten sie Checkpoints manuell und extrem häufig aus. Diese Designentscheidung sollte sich als Zündschnur für das spätere Drama erweisen.

Race Condition: Wenn sich zwei Vorgänge überschneiden

Der Mechanismus des Bugs lässt sich in einem Satz zusammenfassen: Während der Übertragung ins Hauptbuch fand gleichzeitig ein neuer Schreibvorgang statt, wodurch die zeitliche Reihenfolge durcheinandergeriet. In der Fachsprache spricht man von einer Race Condition (Wettlaufbedingung).

Im Detail lief das folgendermaßen ab: Der Checkpoint-Prozess zählte 10 Notizzettel in der WAL-Datei und begann, diese ins Hauptbuch zu kopieren. Mitten in diesem Übertragungsvorgang fügte ein anderer Prozess einen neuen Zettel hinzu und setzte gleichzeitig den Zählerstand der WAL-Datei zurück – woher auch der Name des Bugs „WAL-Reset“ rührt. Der Checkpoint-Prozess bemerkte diesen Reset nicht und übertrug brav nach dem alten Zählerstand weiter. Die Folge: Eine Datenseite, die eigentlich noch gar nicht übertragen war, wurde fälschlicherweise als „bereits erledigt“ eingestuft und übersprungen.

Checkpoint-Ablauf

Abb.: Der Checkpoint-Prozess kopiert Datenseiten aus dem WAL zurück in die Hauptdatenbankdatei. Quelle: tailscale.com

Dieser Buchungseintrag verschwand spurlos. Noch schlimmer: An anderer Stelle im Hauptbuch verwiesen Zeiger (Indizes) weiterhin auf diesen verschwundenen Eintrag, weshalb SQLite die gesamte Datenbank als „beschädigt“ einstufte. Die Ingenieure von Tailscale stießen später auf eine widersprüchliche Zahl in ihren Logs: In der WAL-Datei befanden sich eigentlich nur 10 Seiten Daten, der Checkpoint meldete jedoch stolz, 20 Seiten kopiert zu haben. Die 10 überzähligen Seiten waren ein Phantom-Artefakt des veralteten Zählerstands – und der entscheidende Hinweis zur Lösung des Rätsels.

Warum der Fehler 16 Jahre lang unentdeckt blieb

Das offizielle Entwicklerteam von SQLite schätzt, dass dieser Bug seit mindestens 16 Jahren im Quellcode existierte. Dass er so lange unbemerkt blieb, lag an den extrem unwahrscheinlichen Auslösebedingungen: Es brauchte eine ganz bestimmte Kombination von Softwareversionen, einen Schreibvorgang, der auf die Mikroschrecksekunde genau in ein bestimmtes Zeitfenster des Checkpoints fiel, sowie ein spezifisches Verhalten des Dateisystems. Die Wahrscheinlichkeit, dass alle drei Faktoren im normalen Betrieb zusammentrafen, war – wie es der SQLite-Autor formulierte – „im alltäglichen Gebrauch praktisch unmöglich“.

Um die spätere Korrektur überhaupt testen zu können, mussten die SQLite-Entwickler eigens eine spezielle Testlogik in den Quellcode einbauen, die den Zusammenstoß künstlich herbeiführte – ein Aufwand, den sie noch nie zuvor für einen einzelnen Bug betrieben hatten.

Die meisten Anwender nutzen die Standardkonfiguration und werden diesem Bug in ihrem ganzen Leben nie begegnen. Tailscale traf es 19-mal, weil ihre eigenen, extrem aggressiven Checkpoint-Intervalle die Wahrscheinlichkeit der Überschneidung drastisch erhöhten. Das „unmögliche Ereignis“ wurde in ihrer Umgebung zur Frage der Zeit.

Wie die Detektive den Fall lösten

Unter den vielen technischen Postmortems sticht dieser Bericht durch seine außergewöhnliche Akribie hervor.

Die ersten Monate brachten keinerlei Fortschritt. Sämtlicher eigener Code wurde geprüft – ohne Befund. Es gab keine gemeinsamen Muster, der Fehler ließ sich nicht nachstellen. Zwischenzeitlich gab es sogar eine sechswöchige Phase ohne jeden Vorfall – was im Nachhinein zeigt: Das Ausbleiben von Fehlern bedeutet nicht automatisch, dass ein System gesund ist. Das Team entschloss sich schließlich zu einer radikalen Maßnahme: Jeder einzelne Schreibbefehl an die Datenbank wurde fortan in einer separaten Logdatei protokolliert.

Dieses Protokoll brachte den Durchbruch. Bei zwei darauffolgenden Abstürzen zeigte das Replay der Logdateien: Ein erfolgreich bestätigter Schreibvorgang war nachträglich schlicht „unsichtbar“ geworden. Eine geschriebene Transaktion löste sich stumm in Wohlgefallen auf – was in der Welt der Datenbanken eigentlich unmöglich ist.

Daraufhin schaltete sich das Kern-Entwicklerteam von SQLite ein (Tailscale kaufte dafür kommerziellen Profi-Support). Gemeinsam entwickelten sie ein spezielles Diagnose-Tool namens tmstmpvfs shim („Shim“ bezeichnet eine Überwachungshülle um ein bestehendes Modul). Die Architektur von SQLite besteht vereinfacht aus drei Schichten: Die obere Schicht versteht SQL-Befehle, die mittlere zerlegt die Daten in Blöcke, und die unterste Schicht schreibt die Blöcke auf die Festplatte – diese unterste Schicht heißt VFS (Virtual File System). Das Shim legte sich wie eine hochauflösende Überwachungskamera vor den Tresor und zeichnete jede einzelne Festplatten-Eingabe und -Ausgabe auf.

VFS Shim Diagnose-Schicht

Abb.: Die unterste Speicher-Schnittstelle von SQLite wird von einer Überwachungsschicht (Shim) umhüllt. Quelle: tailscale.com

Nach der Installation der Kamera hieß es Warten. Es dauerte nicht lange bis zum nächsten Vorfall. Die vollständigen Aufzeichnungen wurden den SQLite-Entwicklern übergeben – und die Race Condition wurde auf frischer Tat ertappt: Mitten im Checkpoint hatte eine Schreibtransaktion das WAL zurückgesetzt, ohne dass der Checkpoint dies bemerkte.

Fast zeitgleich meldete eine weitere Front Erfolge: Die auf Softwaretests spezialisierte Firma Antithesis konnte den Bug mithilfe von „Property-based Testing“ (eigenschaftsbasiertem Testen) unabhängig reproduzieren. Das Testwerkzeug generierte riesige Mengen zufälliger paralleler Schreib- und Checkpoint-Sequenzen und überprüfte dabei kontinuierlich zwei eiserne Regeln: „Bestätigte Schreibvorgänge dürfen nie verloren gehen“ und „Die Datenbank darf nie beschädigt werden“. Auf unkorrigierten Versionen schlug der Test an, auf korrigierten lief er fehlerfrei durch. Was sich kein menschlicher Entwickler ausdenken konnte, erledigte die Maschine durch stures Ausprobieren.

Die Reparatur und ein fehlgeschlagener Alarm

Die eigentliche Behebung erforderte nur eine einzige Codeänderung: Eine zusätzliche Prüfung im Checkpoint-Quelltext stellt nun sicher, dass der Vorgang abgebrochen wird, falls ein anderer Thread den WAL-Zähler zurückgesetzt hat. Der Fix wurde mit SQLite Version 3.51.3 veröffentlicht.

Doch die Geschichte war noch nicht zu Ende. Als Tailscale die geflickte Version ausrollte, schlug das Backup-Monitoring sofort großflächig Alarm – angeblich massenhafte Datenbankdefekte. Es stellte sich als blinder Alarm heraus: Eine ältere, minimale Index-Inkonsistenz aus früheren Versionen wurde durch eine Optimierung in der neuen SQLite-Version plötzlich sichtbar gemacht. Das SQLite-Team zog die Version umgehend zurück und veröffentlichte einen sauberen Build, der nur den WAL-Reset-Fix enthielt. Tailscale passte seinerseits die Datenstruktur an. Das Reparieren eines Bugs bringt oft andere Probleme ans Licht – eine Kettenreaktion, die in der Softwaretechnik an der Tagesordnung ist.

Der wichtigste Schritt folgte zum Schluss: Um absolut sicherzustehen, dass der Bug in der eigenen Produktion tatsächlich aufgetreten war, baute Tailscale eine Telemetrie-Warnung ein. Wann immer ein Schreibvorgang und ein WAL-Reset zusammenstießen, sollte das System einen Alarm loggen. Nach dem Deployment blieb es zwei Monate ruhig. Doch nach zwei Monaten schlug das System an – der unwiderlegbare Beweis, dass der 16 Jahre alte Bug tatsächlich in ihrer Produktion aufgetreten war und durch den Fix erfolgreich abgefangen wurde. In den folgenden vier Monaten gab es keinen einzigen Datenbankdefekt mehr.

Den vertrauenswürdigsten Bausteinen gebührt die größte Skepsis

Diese Geschichte enthält eine bemerkenswerte Lektion für die Softwareentwicklung. SQLite gehört zu den vertrauenswürdigsten Softwarekomponenten überhaupt; kein Entwickler hinterfragt seine Zuverlässigkeit beim Start eines neuen Projekts. Doch genau dieses blinde Vertrauen führte dazu, dass ein kritischer Fehler 16 Jahre lang unbemerkt auf Milliarden von Geräten existieren konnte. Wenn das Fundament bröckelt, gerät das gesamte Gebäude darüber in Gefahr – und niemand sucht die Ursache im Fundament.

Die Ingenieure von Tailscale verdienten sich für ihr transparentes Vorgehen breite Anerkennung in der Fachwelt. In den Diskussionen fiel immer wieder das Wort „refreshing“ (erfrischend): Statt die Schuld abzuwälzen, kauften sie offiziellen Support, finanzierten die Entwicklung des Open-Source-Diagnose-Tools und stellten die Erkenntnisse der Allgemeinheit zur Verfügung.

Dass ein Unternehmen Geld in die Hand nimmt, um Open-Source-Projekten maßgeschneiderte Diagnosewerkzeuge zu spendieren, ist in der kommerziellen Welt selten. Für normale Anwender zeigt dieser Vorfall vor allem eines: Hinter den unscheinbaren Softwarekomponenten auf unseren Smartphones stehen Ingenieure, die sich ein halbes Jahr lang festbeißen, nur um einen „praktisch unmöglichen“ Fehler für immer zu eliminieren.

Ein 16 Jahre alter Bug ist Geschichte. Doch wo wartet der nächste? Vielleicht genau jetzt in einer Software auf Ihrem Smartphone, der Sie blind vertrauen.

Referenzen:

  • Tailscale: Postmortem zum SQLite WAL-Reset-Bug
  • Antithesis: Breaking the WAL
  • HN-Diskussion (item?id=49272832)