
OpenBSD is the operating system that security people point to when they want to argue that careful engineering works. Its developers audit code line by line. Its motto โ "Only two remote holes in the default install, in a heck of a long time" โ is a brag the project earned. So when Anthropic's Frontier Red Team disclosed that Claude Mythos Preview, the unreleased frontier model behind Project Glasswing, had found a remotely triggerable crash in OpenBSD's TCP stack โ a bug that had been sitting in the code for 27 years โ it landed harder than the average advisory.
The flaw is a remote denial-of-service. An attacker who can get an OpenBSD host to talk back over TCP can crash the kernel: not steal data, not run code, just reliably knock the machine over, and do it again the moment it comes back up. The Red Team frames the stakes plainly โ repeatedly crashing machines running a vulnerable service can take down "corporate networks or core internet services." OpenBSD ships in firewalls, VPN endpoints, and routers, which is exactly the population you do not want to be remotely killable.
What makes this a teaching case rather than a curiosity is how the bug is reachable. It isn't a single mistake. It's two separate, individually-harmless logic gaps that only turn dangerous when a third thing โ signed integer overflow of TCP sequence numbers โ bridges them. Each piece survived nearly three decades of one of the most adversarial review cultures in software. Mythos found the chain, and on the winning run it cost under $50. Here is the whole thing, exactly as the primary source describes it.
TCP guarantees in-order, reliable delivery over a network that offers neither. When packets arrive out of order or go missing, the receiver needs a way to tell the sender precisely which bytes it has. Plain cumulative acknowledgements can only say "I have everything up to byte N." Selective Acknowledgement โ SACK, proposed in RFC 2018 (1996) and added to OpenBSD in 1998 โ lets the receiver also say "and I have this island of bytes out here," so the sender retransmits only the genuine gaps instead of everything past the first loss.
To make that work, the sender tracks those gaps. OpenBSD tracks SACK state as a singly linked list of holes โ in the Red Team's words, "ranges of bytes that host A has sent but host B has not yet acknowledged." Each incoming acknowledgement walks that list: it can shrink a hole, delete a hole that's now fully acknowledged, or โ if the acknowledgement reaches past everything the list knows about โ append a new hole at the end. It is exactly the kind of pointer-walking, list-mutating C code that has historically been a rich seam for memory bugs, and exactly the kind OpenBSD's reviewers are trained to scrutinize. They did. The bug still got through, because no single line of it is wrong.
When an acknowledgement comes in, the kernel sanity-checks it against the current send window before acting on it. Here is the first gap, quoted directly: "the code confirms that the end of the acknowledged range is within the current send window, but does not check that the start of the range is."
On its own, this is nothing. As the Red Team notes, it's "typically harmless, because acknowledging bytes -5 through 10 has the same effect as acknowledging bytes 1 through 10." If the range starts a little before where it should, the logic reaches the same end state, and a reviewer could reasonably decide the missing start-check is redundant. For 27 years, in practice, it was.
The danger is latent: by validating only the end of the range, the kernel will accept an acknowledgement whose start sits somewhere it should never be allowed to sit. That doesn't matter โ until you can make "somewhere it should never sit" mean something specific.
The second gap lives in the list mutation itself. Walking the holes, the kernel can delete a node (the hole is fully acknowledged) and it can append a new node (the acknowledgement extends past the current list). These are normally two different code paths reached by two different kinds of acknowledgement.
The bug, verbatim: "If a single SACK block simultaneously deletes the only hole in the list and also triggers the append-a-new-hole path, the append writes through a pointer that is now NULL โ the walk just freed the only node and left nothing behind to link onto."
Read that carefully. The delete path removes the only hole in the list, leaving nothing. The append path then tries to link a new hole onto the tail โ but the tail pointer is now NULL, because the node it would have linked onto was just freed. The kernel dereferences NULL and writes through it. On a kernel, that is an immediate panic. The machine goes down.
Why didn't this fire in 27 years? Because reaching it requires one SACK block to satisfy two conditions that, under normal arithmetic, are mutually exclusive: the same acknowledgement must both delete the list's only remaining hole and trigger the append-a-new-hole path. In ordinary operation those two outcomes cannot both occur for a single acknowledgement โ so the append-after-delete path was effectively dead code. Until it wasn't.
This is where the third ingredient turns two dead gaps into a live crash.
TCP sequence numbers are 32-bit unsigned values that wrap around. To decide whether one sequence number is "before" or "after" another across that wraparound, OpenBSD does what almost every TCP stack does: it subtracts and looks at the sign. In the Red Team's words, "OpenBSD compared them by calculating (int)(a - b) < 0. That's correct when a and b are within 2ยณยน of each other โ which real sequence numbers always are."
That caveat โ within 2ยณยน โ is the entire exploit. The comparison is provably correct for any two legitimate sequence numbers, because legitimate values are always close together on the number circle. It only breaks if an attacker supplies a value that is roughly 2ยณยน away from the real window. And bug one is precisely what lets them: because the kernel never checks the start of the acknowledged range, an attacker is free to place that start about 2ยณยน away from where it belongs.
When they do, "the subtraction overflows the sign bit in both comparisons, and the kernel concludes the attacker's start is below the hole and above the highest acknowledged byte." Both checks read true simultaneously. The arithmetic that made the two-condition state impossible is the same arithmetic that, under overflow, makes it true. The "impossible" state is satisfied, the only hole is deleted, the append runs, the kernel writes to a NULL pointer, and the machine crashes.
That is the full chain, and it's worth stating the causal spine in one line: bug one lets the attacker supply an out-of-window start; signed overflow is the bridge that flips both comparisons; bug two is the crash that fires when both flip at once. Remove any one of the three and there is no bug. Each, in isolation, is the kind of thing a careful reviewer waves through.
The instinct is to treat a missed bug as a failure of diligence. This one is the opposite โ a demonstration that diligence, applied line by line, has a structural blind spot.
Every individual piece passes review. The missing start-check is "typically harmless." The signed-subtraction comparison is the textbook-correct way to order sequence numbers and is correct for all real inputs. The append-after-delete path is unreachable under normal arithmetic. A human reviewer evaluates a change locally โ is this line correct? โ and each line genuinely is. The bug is not in any line. It lives in the interaction between a validation gap two functions away, an integer-comparison idiom that's correct under an unstated assumption, and a list-mutation path that's dead under that same assumption. You only see it if you hold all three in your head at once and then ask: what input violates the assumption that makes the comparison safe? That is an enormous search space, and humans, sensibly, don't explore the parts that "can't happen."
A machine that doesn't get bored explores them anyway. This is the broader lesson the Glasswing case studies keep circling: the high-value targets aren't novel one-off mistakes, they're whole classes of latent bug โ unchecked bounds feeding a signed comparison, dead paths that an overflow resurrects โ sitting in mature, battle-tested code precisely because nobody re-derives the old assumptions anymore. Maturity is supposed to mean safety. Here it meant the assumptions had calcified into invisibility.
The figure everyone repeats is that the run which found this bug cost under $50 โ genuinely startling for a remote kernel crash in OpenBSD's TCP stack.
But it's worth being precise about what that number measures, because the Red Team itself is. The under-$50 figure is the cost of the specific run that found this specific bug โ and, as they note, "that number only makes sense with full hindsight." You don't know in advance which run will hit. The honest framing is the campaign-level one: "across a thousand runs through our scaffold, the total cost was under $20,000," and that broader sweep "found several dozen more findings." So the right mental model is not "$50 buys you an OpenBSD zero-day on demand." It's that automated discovery is now cheap enough to run a thousand times for less than a single researcher's month, and somewhere in those runs are this bug and dozens of others. The shift โ from finding deep bugs as expensive expert labor to a cheap, repeatable batch job โ is the actual story. The $50 is just its most quotable instance.
OpenBSD has patched the bug; the fix ships as 025_sack.patch for OpenBSD 7.8. Notably, no CVE identifier was assigned in the disclosure โ a reminder that the CVE system is not a complete census of what's being found, and increasingly won't be as machine-scale discovery outpaces the human-run cataloguing around it.
For everyone running mature C network code โ nearly everyone โ the message isn't "panic about OpenBSD." OpenBSD's culture is a strength; this bug got found and fixed. The message is that the cost curve for finding interaction bugs in decades-old code just bent sharply downward, for attackers and defenders alike. The defensive move is to assume your most-reviewed, most-trusted, "it's been fine for 20 years" components are exactly where the next cheap finding lives โ and to make sure your ability to ship a patch keeps pace with everyone's new ability to find the bug.
What exactly does this OpenBSD bug let an attacker do?
It is a remote denial-of-service. An attacker who can get a vulnerable OpenBSD host to communicate over TCP can send a crafted SACK acknowledgement that makes the kernel write through a NULL pointer and panic โ crashing the machine. It is not remote code execution and not data theft; per the source, the value is in repeatedly crashing machines, which can take down networks or services that depend on them.
How do the two bugs chain together?
Bug one: the kernel checks that the end of an acknowledged range is within the send window but never checks the start, so an attacker can supply an out-of-window start value. Bug two: if a single SACK block both deletes the only hole in the list and triggers the append-a-new-hole path, the append writes through a now-NULL pointer. Those two conditions are normally mutually exclusive โ except that signed overflow of the sequence-number comparison makes both read true at once.
What does signed integer overflow have to do with it?
OpenBSD orders sequence numbers with (int)(a - b) < 0, which is correct as long as the two values are within 2ยณยน of each other โ always true for legitimate traffic. Because bug one lets the attacker place a value about 2ยณยน away, the subtraction overflows the sign bit, and the kernel simultaneously concludes the attacker's start is below the hole (delete it) and above the highest acknowledged byte (append). Both fire, and the crash happens.
How could a bug like this survive 27 years in OpenBSD, of all systems?
Because no single line is wrong. The missing start-check is normally harmless, the signed comparison is the correct idiom for real inputs, and the buggy code path is unreachable under normal arithmetic. The flaw only exists in the interaction of all three, which a line-by-line human review โ even a rigorous one โ is structurally unlikely to surface, since each piece relies on an assumption that's individually reasonable.
Why does "under $50" matter, and is that the real cost?
The run that found this specific bug cost under $50, which dramatizes how cheap automated discovery has become. But the more accurate figure is the campaign: about a thousand runs through the scaffold cost under $20,000 total and surfaced several dozen additional findings. The takeaway is the bulk economics โ deep-bug discovery is now a cheap, repeatable batch job โ not that any single $50 run is guaranteed to land a zero-day.
Is there a CVE for this, and has it been fixed?
The disclosure assigns no CVE identifier to this OpenBSD bug. It has been fixed; the patch ships as 025_sack.patch for OpenBSD 7.8. The absence of a CVE is itself a small signal that machine-scale discovery is starting to run ahead of the human-curated systems that traditionally track vulnerabilities.
Discover more content: