☰ Menu

08.10.2026 · Signal Titans Editorial

Ken Thompson zeigte, wie ein Compiler eine Hintertür sogar vor seinem eigenen Quellcode verbergen kann

Ken Thompson links auf einem dunklen Clean-Modern-Cover mit dezentem Compiler-Flow-Motiv und dem Schriftzug Trust the Tool?

Du prüfst den Quellcode eines Programms Zeile für Zeile. Der gefährliche Code ist nicht vorhanden. Du baust das Programm aus diesem sauberen Quelltext neu. Und trotzdem erscheint das gefährliche Verhalten wieder.

Genau diese beunruhigende Idee stellte Ken Thompson in seiner Turing-Award-Rede von 1983 vor, die 1984 unter dem Titel Reflections on Trusting Trust veröffentlicht wurde. Thompson war längst bekannt als Mitentwickler von Unix und als Schöpfer der Programmiersprache B. Doch dieser kurze Vortrag griff eine besonders beruhigende Annahme der Softwareentwicklung an.

Wenn der Quellcode sauber ist, erwarten wir meist auch ein sauberes Programm. Thompson zeigte, warum dieser Schluss scheitern kann, wenn das Werkzeug, das aus dem Quelltext das Programm erzeugt, selbst nicht vertrauenswürdig ist.

Der Trick beginnt mit einem Compiler, der sich etwas merkt

Ein Compiler übersetzt Quellcode in ausführbaren Code. Viele Compiler sind in derselben Sprache geschrieben, die sie selbst übersetzen. Dadurch entsteht eine nützliche, aber merkwürdige Schleife: Ein Compiler kann eine neue Version seiner selbst kompilieren.

Thompson begann mit einem harmlosen Beispiel. Er erklärte, wie man einem Compiler eine neue Sprachregel beibringen kann und wie dieses Wissen erhalten bleibt, wenn der Compiler später neue Versionen seiner selbst erzeugt. Sobald der kompilierte Compiler die Regel bereits kennt, muss der ursprüngliche Trainingsschritt nicht mehr sichtbar im Quellcode stehen.

Entscheidend war nicht die neue Sprachregel. Entscheidend war die Erkenntnis, dass ein Verhalten im Binärprogramm weiterleben kann, obwohl der Quelltext, der es ursprünglich eingeführt hat, längst verändert wurde.

Dann wird das erinnerte Verhalten bösartig

Thompsons nächster Schritt war bewusst schädlich. Er beschrieb einen Compiler, der erkennt, wenn das Unix-Programm login übersetzt wird, und zusätzliches Verhalten einfügt, das neben dem echten Passwort auch ein bestimmtes bekanntes Passwort akzeptiert. Im veröffentlichten Vortrag schrieb Thompson, dass er einen solchen Fehler tatsächlich in einen Compiler eingebaut hatte.

Bliebe diese Regel offen im Compiler-Quellcode stehen, könnte eine Prüfung sie irgendwann entdecken. Deshalb war der letzte Schritt wesentlich verstörender: Der Compiler sollte auch erkennen, wenn er einen Compiler kompiliert, und das neue Compiler-Binärprogramm sollte beide verborgenen Verhaltensweisen weitertragen.

Nach diesem Bootstrap-Schritt konnte der verräterische Quellcode entfernt werden. Ein sauber aussehender Compiler-Quelltext, der mit dem bereits veränderten Compiler-Binärprogramm gebaut wurde, erzeugte erneut einen veränderten Compiler. Dieser konnte wiederum das Login-Programm verändern und beim Neuaufbau seiner selbst das versteckte Verhalten reproduzieren.

Die Hintertür befand sich damit nicht mehr an der Stelle, an der eine normale Quellcodeprüfung nach ihr suchen würde.

Was Thompson tatsächlich gezeigt hat

Die Geschichte wird manchmal mit „Compilern kann man nicht vertrauen“ zusammengefasst. Das ist zu pauschal. Thompsons Demonstration handelte von einer Vertrauenskette. Eine Quellcodeprüfung zeigt, was im Quelltext steht. Sie beweist nicht automatisch, dass das laufende Binärprogramm exakt diesem Quelltext entspricht, denn ein anderes Programm musste die Übersetzung durchführen.

Thompson betonte außerdem, dass die Idee nicht auf C-Compiler beschränkt ist. Theoretisch könnte auch ein Assembler, Loader, Firmware-Werkzeug oder ein anderes programmverarbeitendes System kompromittiert sein. Je tiefer eine solche Schicht liegt, desto schwieriger kann es werden, das Ergebnis mit Werkzeugen zu untersuchen, die selbst von dieser Schicht abhängen.

Er wies auch darauf hin, dass die grundlegende Angriffsidee älter war als sein Vortrag und verwies auf eine frühere Sicherheitskritik an Multics im Auftrag der US Air Force. Seine Leistung bestand darin, das Problem mit einer kompakten, unmittelbar verständlichen Demonstration in das Bewusstsein vieler Programmierer zu bringen.

Heute heißt die Lehre Software-Supply-Chain-Vertrauen

Moderne Build-Pipelines bestehen aus weit mehr als einem Compiler. Ein Release kann von Paketmanagern, Build-Runnern, Container-Images, Codegeneratoren, Signiersystemen und Bibliotheken Dritter abhängen. Thompsons Beispiel bedeutet nicht, dass alle diese Ebenen heimlich feindlich sind. Es bedeutet, dass Quellcodeprüfung nur ein Teil der Absicherung ist.

Die nützliche Frage lautet: Was musste bereits vertrauenswürdig sein, bevor dieses Binärprogramm entstand?

Darauf reagieren Praktiken wie reproduzierbare Builds, unabhängige Build-Umgebungen, signierte Artefakte, Provenienz-Nachweise und eine stärkere Trennung zwischen Entwicklung und Veröffentlichung. David A. Wheeler untersuchte zudem mit dem Ansatz des diverse double-compiling eine direkte Gegenmaßnahme: unabhängig erzeugte Compiler-Ergebnisse werden verglichen, um unter klaren Voraussetzungen zu prüfen, ob ein Compiler-Binärprogramm seinem behaupteten Quelltext entspricht.

Eine Warnung vor unsichtbaren Abhängigkeiten

Thompsons Vortrag bleibt im Gedächtnis, weil er eine normale Stärke der Softwareentwicklung gegen uns wendet. Programmierer brauchen Abstraktion. Wir verlassen uns auf Werkzeuge, damit wir nicht jede Maschineninstruktion selbst untersuchen müssen. Ohne diese Arbeitsteilung wäre moderne Entwicklung kaum möglich.

Doch jede Abstraktion erzeugt auch eine Abhängigkeit. Sobald ein Team sagt „das macht der Compiler“, „das prüft der Paketmanager“ oder „das erzeugt der Build-Server“, liegt ein Teil des Vertrauens außerhalb der gerade gelesenen Quelldatei.

Die praktische Antwort ist weder Paranoia noch der Versuch, den gesamten Computerstapel selbst von Grund auf neu zu bauen. Vertrauen sollte sichtbar gemacht werden: Welche Werkzeuge gehören zur Kette? Welche Abhängigkeiten sind wirklich nötig? Welche wichtigen Artefakte lassen sich über unabhängige Wege prüfen, wenn das Risiko den Aufwand rechtfertigt? Lesbarer Quellcode bleibt entscheidend, aber er ist nicht der endgültige Beweis dafür, was die Maschine tatsächlich ausführt.

Thompsons Ergebnis nahm dem Quellcode nicht seine Bedeutung. Es zeigte nur, dass Quellcode eine Ebene der Evidenz ist und nicht die gesamte Kette.

Quellen