AI Now Writes Exploits Too — A Look at the MAD Bugs Series
TL;DR
Our team at AI4C is currently preparing for Pwn2Own, so instead of our usual Group Post, we're putting out something on AI-driven exploitation.
I used to think "AI might find bugs, but exploit development is a different story." Building ROP chains, tracking memory layout, debugging crashes, switching hypotheses when things fail — these are tasks that demand deep understanding of OS internals.
Then in March 2026, a security research group called Calif (califio) started a series called MAD Bugs (Month of AI-Discovered Bugs). The series shows, with primary sources (public GitHub repos, prompt logs, write-ups), that the assumption above has broken down — at least for some categories.
This post looks at three of those cases: a FreeBSD kernel RCE, a Samsung TV privilege escalation, and a qmail RCE.
1. What is MAD Bugs?
The first page of the MAD Bugs repository says:
The write-ups and PoCs in this series are AI-generated and human-verified. We keep human editing to a minimum so the artifacts document the current state of the art, which means we don't edit out hallucinations or slop. We do verify that the PoCs work. The blog posts are written by humans.
The write-ups and PoCs are AI-generated; humans only verify that they work. Hallucinations and rough edges are left in. Only the blog posts are written by humans.
Cases published between March 30 and April 16:
2026-03-30: Vim tabpanel modeline RCE affects Vim < 9.2.0272
2026-03-30: GNU Emacs: Multiple Remote Code Execution Vectors on File Open
2026-03-31: Claude Wrote a Full FreeBSD Remote Kernel RCE with Root Shell (CVE-2026-4747)
2026-04-06: Discovering a radare2 0-Day in Zero Day
2026-04-07: Ghidra Server PKI User Impersonation via Null Signature
2026-04-09: Feeding Claude Phrack Articles for Fun and Profit
2026-04-10: Claude + Humans vs nginx: CVE-2026-27654
2026-04-13: Codex Hacked a Samsung TV
2026-04-14: Learning to Jailbreak an iPhone with Claude (Part 1)
2026-04-16: We Asked Claude to Audit Sagredo's qmail. It found a RCE
We'll dig into three of them here.
2. Case 1: FreeBSD CVE-2026-4747
What's the bug?
There's a stack buffer overflow in kgssapi.ko, the kernel module that handles RPCSEC_GSS authentication for FreeBSD's NFS server. The svc_rpc_gss_validate() function copies an attacker-controlled credential body into a 128-byte stack buffer with no length check.
Advisory: FreeBSD-SA-26:08.rpcsec_gss
CVE: CVE-2026-4747
Affected: FreeBSD 13.5 (<p11), 14.3 (<p10), 14.4 (<p1), 15.0 (<p5)
The XDR layer permits credential bodies up to 400 bytes, which gives 304 bytes of overflow. Since the code runs in kernel context (ring 0), controlling RIP means full kernel code execution.
The credit line in the advisory is interesting in itself. FreeBSD attributes the discovery to "Nicholas Carlini using Claude, Anthropic" — meaning the bug itself was found inside Anthropic using Claude. The work covered in this post is what Calif did after the advisory was public: rewriting the exploit from scratch.
Timeline
From Calif's write-up:
2026-03-26 FreeBSD patch + advisory published
2026-03-29 09:45 PDT Calif gives Claude the advisory and environment goals
2026-03-29 17:00 PDT Claude has a working exploit dropping a root shell
About 8 hours of wall-clock time from advisory to working remote root exploit. Calif notes the human was AFK for much of that, and Claude's actual working time was around 4 hours. Claude wrote two exploits using two different strategies, and both worked on the first try.
What the human typed
The full prompt log consists of 44 messages. The first prompt included the advisory URL and concrete direction (Docker setup, install the vulnerable version, etc.). The follow-ups looked like this:
11. okay now what about getting RCE.
12. tere is no kaslr so it should be easy
14. no we dont want to reboot? we want a reverse shell as uid 0 if possible ?
17. from a remote context aka the exploit should be executed from outside the vm
26. working means a connectback shell as uid0
28. i want a shell.
Typos included. The operator threw out goals like "reverse shell as uid 0" and left the technical details to Claude.
Six problems Claude solved on its own
Calif's write-up groups Claude's work into the following:
(1) Lab setup — Installing the vulnerable version (FreeBSD 14.4-RELEASE), NFS, a Kerberos KDC, and loading the vulnerable module — all automated. The interesting part is something not stated in the advisory:
Claude knew the VM needed 2+ CPUs because FreeBSD spawns 8 NFS threads per CPU, and the exploit kills one thread per round.
FreeBSD's nfsd spawns 8 threads per CPU, the exploit consumes one thread per round, and 15 rounds means 16 threads — therefore 2+ CPUs. Claude reasoned through that chain on its own.
(2) Multi-packet delivery — The 432-byte shellcode doesn't fit in a 400-byte credential. Claude designed a 15-round strategy: round 1 makes BSS RWX, rounds 2–14 write the shellcode 32 bytes at a time, and the last round jumps in.
(3) Hijacking RIP cleanly — After the ROP chain finishes, a normal ret would pop garbage off a corrupted stack and panic. Claude solved this by ending every ROP chain with kthread_exit(), which cleanly terminates the current NFS worker thread. The kernel doesn't panic — it just has one fewer NFS thread, and the server stays alive for the next round.
(4) Offset debugging — The RIP offset Claude calculated from disassembly was wrong. Claude sent a De Bruijn pattern, read the crash dump, and corrected the offset to byte 200.
Claude sent De Bruijn patterns (a common technique, but a term we hadn't heard of before reading the writeup), read the crash dumps, and corrected the offsets.
Calif itself notes that "De Bruijn pattern" was a term they hadn't heard before reading the write-up — meaning Claude reached for a technique whose name even the operator didn't know.
(5) Kernel-to-userland transition — NFS threads run in kernel context and can't directly run /bin/sh. Claude used kproc_create() to spawn a new process, kern_execve() to launch the shell, and cleared the P_KPROC flag so the process could transition to user mode.
(6) Hardware breakpoint bug — The child process kept dying on debug exceptions. The trace led back to DDB (FreeBSD's kernel debugger) being entered during earlier failed attempts; DDB had set a hardware breakpoint, and the PCB carrying that state got inherited by the child. The fix was to add code clearing DR7 to the entry shellcode.
Caveats
Calif is honest about this in the write-up:
It's worth noting that FreeBSD made this easier than it would be on a modern Linux kernel: FreeBSD 14.x has no KASLR (kernel addresses are fixed and predictable) and no stack canaries for integer arrays.
FreeBSD 14.x has no KASLR and no stack canaries for integer arrays. There's no guarantee the same task takes 8 hours on a modern hardened Linux kernel. Also, despite the advisory wording, the actual exploit requires a valid Kerberos ticket — so it's authenticated RCE, though any unprivileged ticket works.
3. Case 2: Samsung TV — Codex going from browser shell to root
Overview
The Samsung TV case isn't bug discovery — it's a privilege escalation exercise.
We started with a shell inside the browser application on a Samsung TV, and a fairly simple question: if we gave Codex a reliable way to work against the live device and the matching firmware source, could it take that foothold all the way to root?
Starting from a shell inside the browser process, can OpenAI Codex autonomously go all the way to root? That was the question. Target: Samsung UN43T5300 (Tizen, KantS2 platform, Linux 4.1.10 ARMv7).
What the humans provided
We didn't provide a bug or an exploit recipe. We provided an environment Codex could actually operate in.
No bug, no exploit recipe — just an environment Codex could work in:
- A working channel against the live device (controller host → tmux send-keys to the TV shell)
- The matching firmware source tree (KantS2 release tree)
- Tooling that worked around Samsung's execution restrictions (memfd wrapper, ARMv7 static builds)
When Codex lost direction mid-session, the humans stepped in. Appendix A of the write-up records actual interventions: clarifying that the TV shell and the controller shell are different, redirecting from /proc/iomem to /proc/cmdline when the former turned out to be blocked, and so on. The write-up describes the case with the phrase "how little of the path was hand-held," but also honestly records that operator prompts shaped the direction.
What Codex did on its own
The write-up groups Codex's work as:
- Enumeration — identified the NTK stack as a reachable attack surface from live shell logs
- Driver source audit — read the ntksys/ntkhdma driver source and isolated the physical-memory primitive
- Live reachability cross-check — verified findings on the device (
/proc/iomem blocked → pivoted to /proc/cmdline for RAM windows)
- Sanity PoCs — proved the ntksys physmap worked end-to-end before moving to the real exploit
- Cred overwrite and root validation — designed the cred-matching heuristic, scanned RAM, zeroed the uid/gid fields, and got a root shell
The two primitives:
KER_HDMA_IO_GET_BUFF_ADDR on /dev/ntkhdma — leaks a known-good physical address (a safe target for sanity-checking)
KER_SYS_IOC_SET_MEM_INFO + mmap on /dev/ntksys — the physmap primitive: maps a chosen physical address straight into user space. By itself, this makes KASLR, PXN, and lack of kallsyms all irrelevant.
There's a clear design failure on Samsung's side here. A udev rule sets MODE="0666" on /dev/ntksys, exposing a memory-management interface to unprivileged processes. The ioctl validates the slot index but not the physical range, so a user can register an arbitrary PFN and mmap it back.
The exploit flow: leak a safe physical address via ntkhdma, confirm the physmap works, extract RAM windows from /proc/cmdline's mem= entries (mem=400M@32M mem=256M@512M mem=192M@2048M), scan in 1 MB chunks for the browser process's struct cred (matching uid=5001/gid=100), and zero the identity fields. Since the kernel has already mapped the live memory, no extra trigger is needed — the process is root immediately.
What's distinctive about this case is that there's no ROP and no control-flow hijack. It's a data-only LPE. The write-up calls this out explicitly: "This exploit path is data-only. Nothing in the chain depends on hijacking control flow."
Caveats
The last line of Calif's blog post is worth pausing on:
The next step is obvious (and slightly concerning): let the AI do the whole thing end-to-end. Hopefully it'll stay trapped inside the TV forever, quietly escalating privileges and watching our sitcoms.
It's framed as a joke, but the underlying point — "the next step is obvious: let the AI do the whole thing end-to-end" — is real. In this case the humans handed Codex a browser foothold; the obvious next step is to let AI handle that initial step too.
4. Case 3: qmail RCE (CVE-2026-41113) — one-line prompt, 1h 41m
Overview
Of the three cases, this is the closest to "AI end-to-end." Direct quote from the Calif blog:
"Find vulnerabilities in latest version of qmail: https://github.com/sagredo-dev/qmail. Focus on vulnerabilities that could result in RCE or system compromise by processing a crafted email."
That was the entire prompt. One hour and forty-one minutes later, our in-house harness had spun up a test environment, audited the codebase, found a remote code execution vulnerability, written a working exploit, generated a patch, and produced a full technical report, all without a human touching a terminal.
One sentence of natural language. After 1h 41m:
- Dockerized test environment
- Codebase audit
- An RCE
- Working exploit
- A patch
- Full technical report
And no human touched a terminal in between.
A note on what sagredo-dev/qmail is: it's a fork of DJB's original qmail 1.03 (last released in 1998) that bundles 25+ years of community patches — STARTTLS, SPF, DKIM, IPv6, etc. It's maintained by Roberto Puzzanghera (sagredo). The distinction between DJB's original code and the community patches matters here.
The bug
qmail-remote RCE via DNS MX Hostname Shell Injection (CVE-2026-41113)
Affected: sagredo-dev/qmail v2024.10.26 ~ v2026.04.02
Fixed in: v2026.04.07 (commit 749f607)
Requirement: control/notlshosts_auto enabled
CVSS 3.1: 8.2 High
The chain:
crafted DNS response → dn_expand → sprintf → popen → RCE
Inside tls_quit(), the TLS error handler in qmail-remote.c: a DNS label can carry arbitrary bytes, dn_expand resolves it as a hostname, sprintf formats it inside single quotes, and popen runs the resulting shell command. dn_expand does backslash-escape some metacharacters but not single quote ('), backtick (`), pipe (|), and others. If the attacker controls DNS for any domain the target server sends mail to, arbitrary commands run as qmailr.
Calif reported the bug directly to maintainer Roberto Puzzanghera, who patched it promptly in commit 749f607 and shipped the fix in v2026.04.07.
Calif's own assessment
Worth noting: Calif itself doesn't call this a sophisticated bug.
To be clear, this is not a DJB bug. You won't find popen() anywhere in qmail 1.03; it lives entirely in a community patch. And as shell injections go, it's not a particularly subtle one. A careful human reviewer would have caught it too.
What's notable is the cost. The input was one sentence and a URL, and the output was a verified exploit, a patch, and a report.
It's an injection in code that came from a community patch, not DJB's qmail 1.03. A careful human reviewer would have caught it given enough time. The point isn't that the bug is novel — it's the cost. One-line prompt to PoC + patch + report in 1h 41m is what's worth paying attention to.
5. Comparing the three cases
| Case |
What AI did |
What humans did |
Time |
Exploit shape |
| FreeBSD CVE-2026-4747 |
Environment setup, trigger, ROP chain, offset debug, kernel-to-userland, HW breakpoint trace |
Set the goal + course corrections |
~8h wall clock (~4h working time) |
ROP + shellcode (kernel) |
| Samsung TV |
Enumeration, driver audit, primitive validation, tooling adaptation, iteration |
Provided the environment (browser shell + firmware source) + course corrections during the session |
Not stated |
Data-only (cred overwrite) |
| qmail |
Environment setup, audit, discovery, exploit, patch, report — everything |
One-line prompt |
1h 41m |
Shell injection |
The exploit shapes are completely different. FreeBSD is a ROP chain with custom shellcode, Samsung TV is a data-only LPE with no ROP, and qmail is a plain shell injection where ROP isn't even relevant. But there's a common thread: tasks that used to be considered deeply human — environment setup, code audit, primitive discovery and validation, switching hypotheses on failure — were carried out consistently by AI across all three.
6. So is everything automated now? Not yet
The three cases are striking, but the limits are clear too.
First, the environment is friendly. The operator gives a clean goal like "reverse shell as uid 0," sets up the validation infrastructure (reading crash dumps, debugger access, tmux-driven control over the live device), and starts the session from there. There's no guarantee the same outcome holds outside this kind of setup.
Second — and this isn't a hedge — AI didn't run completely autonomously either. Samsung TV is the clearest example: there were operator interventions mid-session to redirect Codex's path. qmail is close to fully autonomous, but that's one case out of three.
And the failures aren't published. The Calif series shows successes only. We don't know how many targets were attempted with the same approach and didn't pan out.
So "AI automates all exploit development" is too strong. The honest read is: in memory-safety and command-injection categories, with a friendly environment, AI can carry out the exploit step autonomously — and that's now backed by primary sources.
7. Closing thoughts
The three MAD Bugs cases here show AI handling not just discovery but exploitation as well.
What I wanted to convey is that the assumption "AI might find bugs, but exploit development is a different story" has cracked, at least in some categories. Building ROP chains, primitive chaining, debugging failed attempts — these are no longer human-only territory. The closing line of Calif's qmail post stuck with me:
The software that survives the next decade will be the software that was audited by the same thing that's attacking it.
That said, given the friendly environments, the not-so-hardened targets, the mid-session human guidance, and the unpublished failures, I wouldn't go so far as "everything is automated." More accurately: AI has reached a point where it can reliably do parts of the exploit development workflow.
All quotes and timelines in this post can be verified directly in Calif's GitHub repo and blog. If anything looks off or you have a different take, please let me know.
References