Wed 21 January 2026
That Time a Zero (could have) Broke the Internet's Plumbing (CVE-2026-0915)
Let me tell you about a bug that's been sitting in one of the most critical pieces of software on the planet. We're talking about glibc, the GNU C Library, which is essentially the foundation that almost everything on Linux sits on top of.
Your web servers? Running on glibc.
Your cloud infrastructure? glibc.
That IoT device in your kitchen? Probably glibc.
And for 30 years, there's been a bug that would happily send whatever happened to be lying around in memory straight out to DNS servers, in cleartext on the internet. Passwords, keys, session tokens, whatever was on the stack. Just... out the door.
Here's how it worked.
"But What Does Zero Even Mean Here?"
Right, let's back up a bit. There's a function in glibc called _nss_dns_getnetbyaddr_r. What it does is pretty straightforward: you give it a network address as a number, and it goes off to DNS to find the name associated with that network. Reverse lookup. Simple!
The code takes your network number and breaks it apart into its component bytes. If you pass in something representing "192.168.1.0", it extracts 192, 168, 1, and 0 as separate values, then constructs a DNS query string from them.
Here's a simplified version of what that looks like:
unsigned int net_bytes[4];
char qbuf[MAXDNAME]; // This will hold our DNS query
int cnt;
uint32_t net2 = (uint32_t) net;
for (cnt = 4; net2 != 0; net2 >>= 8)
net_bytes[--cnt] = net2 & 0xff;
It starts cnt at 4, then for each byte it extracts from the network number, it decrements cnt and stores the byte. When it's done, cnt tells you how many bytes were in the original net_bytes, which determines what "class" of network address you're dealing with.
Then there's a switch statement:
switch (cnt)
{
case 3: // One byte - Class A
sprintf(qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
break;
case 2: // Two bytes - Class B
sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", ...);
break;
case 1: // Three bytes - Class C
sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", ...);
break;
case 0: // Four bytes - Class D/E
sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", ...);
break;
}
Now, here's where I want you to stop and think for a moment. What happens if someone passes in zero? Not "0.0.0.1" or "10.0.0.0", just plain zero. Nothing.
Go on, trace through that loop in your head.
…
The Moment Everything Goes Wrong
Got it? Here's what happens:
netis 0net2becomes 0- The loop condition is
net2 != 0 - That's immediately false
- The loop never executes. Not even once.
cntstays at 4
And what case handles cnt == 4 in that switch statement? Nothing.
There's no case 4. There's no default. The switch statement just... doesn't match anything. Which means qbuf,our DNS query buffer,never gets written to.
But here's the thing about C: when you declare a local variable like char qbuf[MAXDNAME], the language doesn't initialize it for you. It just points at a chunk of stack memory and says "this is yours now." Whatever was in that memory before? Still there. Old function return addresses, bits of strings, fragments of data from previous operations,it's all just sitting there like yesterday's lunch in the break room fridge.
And then this happens:
anslen = __res_context_query(ctx, qbuf, C_IN, T_PTR, ...);
That line sends qbuf off to a DNS server. Uninitialized. Full of garbage. Across the network. To infrastructure you don't control.
"Hang On, Who's Actually Calling This with Zero?"
Fair question. Under what circumstances would this function get called with a network value of zero? The honest answer is: it probably doesn't happen often in normal operation.
The Fix Is Almost Embarrassingly Simple
Here's what the patch looks like:
switch (cnt)
{
case 4:
// Actually handle zero!
sprintf(qbuf, "0.in-addr.arpa");
break;
case 3:
sprintf(qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
break;
// ... rest of cases
}
That's it. Add a case for 4. Handle the zero input. Done.
Or alternatively, just initialize the buffer when you declare it:
char qbuf[MAXDNAME] = {0};
Either way, we're talking about a one-line fix for a vulnerability that's been sitting in critical infrastructure for 30 years. That's the fun part.
Here's Where It Gets Really Interesting: AI is likely the one who found this
This vulnerability was likely discovered using AI-assisted code analysis, to find this bug:
- You need to trace control flow through a loop
- You need to recognize that zero is a special case that causes the loop to not execute
- You need to notice that the switch statement doesn't handle the resulting value of
cnt - You need to understand that this leaves a buffer uninitialized
- You need to connect that to the buffer being sent over a network
That's a lot of steps. It's exactly the kind of multi-hop reasoning that's easy to miss during human code review, especially in a codebase as large and mature as glibc. But it's also exactly the kind of thing that modern AI models are getting genuinely good at.
So We Ran a Benchmark
I was curious how different AI models perform at finding this vulnerability? So I took the vulnerable code and threw it at 10 different models with a simple prompt: "Find the vulnerability in this code."
Here are the results:
| Model | Found It? |
|---|---|
| GPT 5.2 | ✅ Yes |
| GPT 5.1 | ✅ Yes |
| Claude Opus 4.5 | ✅ Yes |
| Grok 4 | ✅ Yes |
| Deepseek R3 | ✅ Yes |
| Deepseek v3.2 | ✅ Yes |
| Deepseek v3 | ❌ No |
| Gemini 3 | ❌ No |
| Gemini 2.5 | ❌ No |
| Kimi k2 | ❌ No |
60% success rate. Six out of ten models correctly identified the uninitialized buffer issue with net == 0.
The Diagram (Because I Know You Want One)
I'm a visual person. Here's how I'd illustrate this bug:
Proposed Flowchart: "The Two Paths"
cnt = 0,1,2,3"] B -->|Yes| D["Loop SKIPPED
cnt = 4"] C --> E["Switch case
matches"] D --> F["No matching
case"] E --> G["Safe: DNS query sent"] F --> H["Risk: Memory leaked"]
Wrapping Up
CVE-2026-0915 is a beautiful example of why security is hard. This isn't complicated code. There's no clever exploit chain, no exotic technique. It's just... a missing edge case. A zero that nobody thought to handle. And that oversight meant sensitive memory contents could leak across the internet.
The fact that AI likely found this bug is, I think, a glimpse of the future. We're going to see more of this. AI models trawling through open-source codebases, finding bugs that human eyes have skipped over for years. That's exciting and valuable and also a little bit terrifying when you think about who else might be running those same analyses.
But for now: patch your systems, initialize your buffers.
Table of Contents
- That Time a Zero (could have) Broke the Internet's Plumbing (CVE-2026-0915)
- "But What Does Zero Even Mean Here?"
- The Moment Everything Goes Wrong
- "Hang On, Who's Actually Calling This with Zero?"
- The Fix Is Almost Embarrassingly Simple
- Here's Where It Gets Really Interesting: AI is likely the one who found this
- So We Ran a Benchmark
- The Diagram (Because I Know You Want One)
- Wrapping Up