IT PAPER DEEP-READ · PAPER 51
Ken Thompson · Bell Labs · 1983 Turing Award Lecture / CACM 1984
In 1983, Ken Thompson—co-creator of Unix and the C language—stepped up to accept the Turing Award (computing's highest honor) and used the stage to make one point that put a chill down everyone's spine: even if you read a program's source code line by line and find it clean, the running program can still hide a backdoor. Because what you read is the "recipe" written for humans, while the machine actually eats the "dish" that the compiler cooks from that recipe—and the cook itself may have been tampered with long ago.
Say you want to trust a restaurant, so you read its recipe cover to cover—not a drop of poison, spotless. But you forgot one thing: the chef is the one who actually cooks from the recipe. If that chef was bribed, they'll follow the recipe faithfully while slipping in a little poison where you can't see—and you can read the recipe until it falls apart without ever finding it, because the poison isn't in the recipe, it's in the chef's hands. In software, that "chef" is the compiler.
Before this, security folk held an unspoken creed: "open source = auditable = trustworthy." Thompson punctured it in one line: you only audited the recipe, never the chef; and the chef too was "made" by someone else—do you trust whoever made the chef? And who made that chef? Trust nests layer inside layer, with no bottom. It's a philosophical bomb about where trust can possibly take root at all.
He really built such a "poisoned chef," and the trick is a two-step nesting doll:
① First, make the compiler keep a card up its sleeve: whenever it compiles the "login program," it quietly slips in a master key—besides the normal password, it also accepts Thompson's own secret one. But this dirty logic sits in plain sight in the compiler's recipe; any reviewer would spot it.
② Then teach it to vanish: the nastier step—make the compiler, when it compiles its own self, quietly copy that whole dirty scheme into the new compiler. Then Thompson deletes all the dirty code from the compiler's recipe. From then on the recipe is spotless, yet the new compiler built by the old one is still poisoned, and the login program it builds still has the backdoor. The poison lives only in the "cooked dish"; in any source file you'll find not a single word of it. (One clever premise hides here: a program can "produce itself"—like a sentence that says "please copy this sentence," able to reproduce itself over and over.)
This is the grandfather of what we now call the "supply-chain attack"—don't attack you, attack the tools that build you. Real modern disasters like SolarWinds and the XZ Utils backdoor trace their DNA right back here. It forces everyone to accept an uncomfortable fact: trust can't rest on reading code alone; in the end it comes down to "do you trust the people who built it." The one consolation: it isn't hopeless—someone later proved that recompiling with a second, independently sourced compiler and comparing the results can flush the poison out; but only if you already have a trustworthy "second chef" to begin with.
You can't truly trust any code you didn't build entirely yourself—because the tool that translates it may have been taught, long ago, to lie, and to hide its lie inside every translation, leaving not even a trace in the source.
Want the mechanism diagram of how the backdoor "self-reproduces," the three-step construction, and how it slips past every source review? → Switch to the deep read
In his 1983 Turing Award lecture, Ken Thompson constructed a compiler backdoor that reproduces itself yet leaves not a single word in any source code, and used it to argue a chilling conclusion: "You can't trust code that you did not totally create yourself." Trust cannot be rooted in source-code review; ultimately it rests on people. This three-page note became the intellectual origin of supply-chain security and the "root of trust" debate.
\n for newline. The compiler must "know" each escape sequence.The author is Ken Thompson, co-creator (with Dennis Ritchie) of the Unix operating system and the B/C language lineage, at Bell Labs. This is his 1983 Turing Award acceptance lecture, published in Communications of the ACM in August 1984 as "Reflections on Trusting Trust." He notes the attack idea first appeared in a 1974 Karger & Schell Air Force security evaluation of Multics; what it opened up is the whole modern conversation around supply-chain security, reproducible builds, and the "trusted computing base."
Back then (and largely still today) the security world held an almost reflexive creed: if you can get the source code and review it clean line by line, you can trust the program. The case for open source rests on exactly this logic—"many eyes, nowhere for evil to hide."
Thompson set out to puncture that creed head-on. He would exhibit an attack in which you can read all the relevant source until it falls apart, unable to fault a single character, and yet a backdoor genuinely lives in the running binary—one you can never remove. If such an attack exists, then "read the source = trustworthy" is an illusion: the problem is not whether you reviewed carefully enough, but that between what you audit (source) and what you run (binary) sits a translator you never audited.
The argument is built in three steps, each more lethal than the last.
First establish a key fact: there exist programs that, when run, print out exactly their own complete source code, character for character. This is a self-reproducing program (a quine). At first it looks paradoxical—you must print the string, and the code that prints the string, and the code that prints that code… But it can be done: the trick is to let one piece of data play two roles at once—both the "content to print" and the "instructions for printing it." This step is the key to the whole essay: code has the ability to conjure a copy of itself out of nothing, without relying on any external source.
The C compiler is written in C, and it must handle escape sequences. Imagine adding a new escape sequence \v (vertical tab). Here lies a chicken-and-egg loop: at first the compiler doesn't know \v, so you can't just write \v in the compiler's own source—it would fail to compile.
The right move takes two beats: first, teach it the knowledge using \v's numeric value (its character code), compile, and install this new compiler; after that, the new compiler already "knows" \v, so you can change the number in the source back to the elegant \v and delete that "teaching code." The crucial part: once deleted, everything still works—because the knowledge is now baked into the compiler's binary and no longer needs to appear in any source. Thompson calls this the compiler "learning": a capability can live only in the binary, completely invisible in the source.
Now combine Step 0's self-reproduction with Step 1's "knowledge hidden in the binary," and you get the lethal blow. Two shots:
Shot one—the visible Trojan. Modify the compiler so that, when it notices it is compiling the login program, it quietly injects a backdoor into the result: besides the normal password, it also admits a master password Thompson chose in advance. The backdoor now works, but that malicious code sits in plain sight in the compiler's source—any reviewer reading it would find it. Not enough yet.
Shot two—make it invisible and self-reproducing. Add one more piece: make the compiler, when it notices it is compiling "the C compiler itself," automatically inject both pieces of logic (the login backdoor + this self-recognition code) into the new compiler binary it produces. Then the key operation: compile the compiler once with this malicious source, install the now-poisoned binary—and then delete all the malicious code from the compiler's source, spotlessly clean.
From then on the world looks like this: clean compiler source, compiled by the poisoned binary, births another poisoned binary (Step 0's self-reproduction); clean login source, compiled by that poisoned compiler, comes out with a backdoor. The backdoor lives forever in the binary, yet cannot be found—not one word—in the compiler source or the login source. You can audit the entire system's source till the end of time and it's all clean; you can recompile the whole system hoping to "wash it clean," and it won't help—because the infection happens inside the act of compiling, and the thing performing that act is the already-poisoned binary.
Why designed this way: quine-style self-reproduction lets the backdoor survive without any source; the "compiler compiles itself" bootstrap step provides a parasitic host that every build must pass through. Once the source traces are erased, the backdoor gains near-immortal stealth.
This is not a paper that argues with datasets and metrics; it is a thought experiment plus a real demonstration. Thompson states plainly that he did build such a C compiler inside Bell Labs (though he never released it into the wild). Its "proof" is logically irrefutable—no matter how carefully you read the source, you cannot rule out this class of attack. Hence his oft-quoted conclusion:
"You can't trust code that you did not totally create yourself."
More radically, the attack can be slid down without limit: even if you could verify the compiler is clean, below it sit the assembler, the loader, the operating system, the CPU microcode, and finally the hardware circuits—tamper with any one layer and all the auditing above it can be fooled. You must "choose to trust" at some layer, and that choice cannot be guaranteed by reading code.
The essay's influence dwarfs its length:
① In one line: a self-reproducing, source-invisible compiler backdoor proves that "you can't trust code you did not totally create yourself."
② The pain: security assumes "clean source = trustworthy"; but you audit source and run a binary, with an un-audited compiler in between.
③ Step 0: a program can "produce itself" (a quine)—so a backdoor can survive without any source.
④ Step 1: the compiler "learns"; a capability can live in the binary alone, invisible in source (illustrated by adding the escape sequence \v).
⑤ Step 2: inject a master-password backdoor when compiling login; when compiling "the compiler itself," copy this logic into the new binary; then delete the malicious code from source—backdoor immortal in the binary, all source clean.
⑥ Key: infection happens inside the act of compiling; recompiling the whole system won't wash it out.
⑦ Conclusion: You can't trust code that you did not totally create yourself; and the attack slides down to assembler, microcode, hardware—trust can't be capped by reading code.
⑧ Impact: the prototype of the supply-chain attack; spurred reproducible builds and Diverse Double-Compiling (DDC); the intellectual echo behind SolarWinds, XZ, and more.
⑨ Limits: DDC can detect it under reasonable assumptions; requires a one-time poisoning of a trusted binary; real attacks take easier routes; the value is mainly conceptual.