03 — Secure C and CVE Literacy¶
Every serious C engineer can read a CVE writeup, find the vulnerable line, and describe the fix in one paragraph. This is not “security researcher” territory; it is baseline literacy for anyone who ships C. study partners at Cloudflare, Nvidia, and the Valkey team will ask you about CWE-120 by name. You should be able to answer without googling.
This file covers (1) the CWE top-25 filtered to what applies to C, (2) five concrete 2024–2026 CVEs with the vulnerable pattern named, and (3) how bugs actually become CVEs — the pipeline from fuzzer crash to public disclosure.
The C-specific CWE cheat sheet¶
MITRE publishes an annual “Top 25 Most Dangerous Software Weaknesses.” Roughly half apply anywhere; the ones below are the C-and-C++-only class. Memorize these codes; they show up in every serious postmortem.
CWE |
Name |
One-line pattern |
Typical fix |
|---|---|---|---|
CWE-119 |
Improper restriction of ops within buffer |
|
Bounds check + |
CWE-120 |
Classic buffer overflow (“strcpy without check”) |
|
|
CWE-121 |
Stack-based buffer overflow |
|
Same, plus |
CWE-122 |
Heap-based buffer overflow |
|
Recompute size after validation |
CWE-125 |
Out-of-bounds read |
|
Off-by-one hunt |
CWE-190 |
Integer overflow / wraparound |
|
|
CWE-191 |
Integer underflow |
|
Signed pre-check |
CWE-401 |
Missing free (memory leak) |
Any |
|
CWE-415 |
Double free |
|
Set |
CWE-416 |
Use-after-free |
|
Same; run ASan |
CWE-457 |
Use of uninitialized variable |
|
|
CWE-476 |
NULL pointer dereference |
|
Check every malloc return |
CWE-590 |
Free of non-heap memory |
|
Only free what malloc gave you |
CWE-134 |
Uncontrolled format string |
|
|
CWE-787 |
Out-of-bounds write |
|
Bounds check every index |
One rule that eliminates 60% of these: never call a str* function that does not take a length. strcpy, strcat, sprintf, gets — banned. Use strncpy + explicit NUL termination, strlcpy where available (glibc 2.38+), snprintf, fgets. Modern C23 also gives you <stdckdint.h> for checked integer math.
Five recent CVEs to actually read¶
Do not just note the CVE number. Open each writeup, find the vulnerable commit, read it, and write two sentences in your notes about what would have prevented it. The pattern-recognition builds fast.
CVE-<phone_number_or_numberic_id_or_random_id_24> — Palo Alto PAN-OS pre-auth stack overflow (May 2026)¶
Pre-authentication stack buffer overflow in the User-ID Auth Portal (captive-portal parsing) leading to remote code execution as root. Textbook CWE-121: a fixed-size stack buffer, an unchecked memcpy sized from a client-controlled header field. The fix was a length check before the copy plus stack canaries getting exercised on the crash path. This is why -fstack-protector-strong and -D_FORTIFY_SOURCE=3 are not optional.
Primary source: NVD entry at <https://nvd.nist.gov/vuln/detail/CVE-<phone_number_or_numberic_id_or_random_id_25>>. Palo Alto advisory at security.paloaltonetworks.com.
CVE-<phone_number_or_numberic_id_or_random_id_26> — Samsung Exynos Wi-Fi driver NL80211 overflow (April 2026)¶
Buffer overflow in the Samsung Exynos kernel Wi-Fi driver via the NL80211 netlink interface. Affects Exynos 850, 980, 1280, 1330, 1380, 1480, 1580, and W-series 920–1000. Classic CWE-120: a driver copies attribute data into a fixed-size buffer without validating the netlink attribute’s length field. No authentication required beyond “be on the same Wi-Fi network.” This is the pattern in every kernel driver CVE from the last decade.
Lesson: driver code that trusts a length field from userland or from a peer device is CVE-inevitable. Always cap with a min(user_len, sizeof(buf)) and then treat the excess as an error, not a truncation.
CVE-<phone_number_or_numberic_id_or_random_id_27> — SolarWinds Web Help Desk RCE (2025–2026 exploitation)¶
Disclosed 2025, still under active exploitation in 2026 (per CISA KEV additions). Java-family root cause but the C lesson is a meta-lesson: the fix ships and users don’t apply it. This is why long-term-support branches and backport discipline (see 04_portability_and_abi.md) matter as much as the initial patch. A CVE is not resolved when the maintainer commits the fix; it is resolved when the last customer upgrades.
CVE-<phone_number_or_numberic_id_or_random_id_28> — Windows exFAT heap-based buffer overflow (June 2024)¶
Crafted USB stick triggers a heap overflow in the Windows exFAT driver on mount. CWE-122. The interesting angle is the attack surface: the physical layer. File systems, USB stacks, and Bluetooth stacks are attack surface even before login. This is why kernel-mode C is a different discipline: your input is not “a user”; it is “anyone within physical reach.”
CVE-<phone_number_or_numberic_id_or_random_id_29> — Windows RRAS unauth network RCE (CVSS 8.8)¶
Heap-based buffer overflow in Windows Routing and Remote Access Service, remotely triggerable, no auth. CWE-122. Same shape as the Exynos CVE at a different layer of the stack. Read the Microsoft advisory then look at the CVSS decomposition (AV:N/AC:L/PR:N) — network vector, low complexity, no privileges required. That decomposition is why unauth network C code is scored so harshly and why fuzzing network parsers is where security teams spend most of their budget.
The bonus curl CVE reading list¶
curl publishes every one of its CVEs at https://curl.se/docs/vuln.html with the vulnerable commit hash, the fixing commit, and Daniel Stenberg’s own postmortem. This is the single best CVE-education resource in open source. Read three of them; you will spot the same three patterns.
Specifically look for the ones with subtitles containing “buffer overflow,” “double free,” or “integer overflow” — those are your textbook cases.
From fuzzer crash to public CVE — the pipeline¶
Understanding this pipeline demystifies security work. It is not magic; it is a workflow.
Fuzzer finds crash. OSS-Fuzz or a private harness produces a minimized input that segfaults or triggers ASan.
Triage. Is it exploitable (memory corruption) or a plain DoS (assert failure)? Exploitable → CVE track.
Private disclosure. Reporter emails the project’s security contact (
security@curl.se,security@valkey.io). PGP if the project asks for it.Fix developed in private branch. Maintainer + reporter iterate.
CVE ID requested from CNA. MITRE for most projects; some (Red Hat, Google, GitHub) are their own CNAs.
Coordinated release. Fix commit + advisory + CVSS score + credit — published together, usually on a scheduled day.
Public disclosure. oss-security mailing list, NVD entry, distro backports.
Curl’s typical timeline from private disclosure to public CVE is 2–4 weeks; Google’s Project Zero uses a hard 90-day deadline; Linux kernel varies from days to months. Read one full timeline (curl publishes them) and you will never treat a security bug the same way.
The oss-fuzz-gen story — why LLMs matter here¶
In November 2024, Google’s oss-fuzz-gen project used LLMs to generate fuzz harnesses and found 26 new vulnerabilities across mature projects, including a 20-year-old bug in OpenSSL. The lesson is not “AI is magic”; the lesson is that the harness is often the bottleneck — the fuzzer had the muscle to find these bugs years ago, but no human had written a harness that exercised the vulnerable API. Writing harnesses is now high-leverage security work, and something you can do without being a security researcher.
What most people get wrong about this¶
They think “secure C” is about knowing arcane exploitation techniques (ROP chains, heap grooming). It isn’t. Secure C is about knowing the fifteen patterns above and never writing them. 99% of CVEs in C are one of those fifteen patterns, and 99% of those are caught by -Wall -Wextra -D_FORTIFY_SOURCE=3 + ASan + a fuzz harness. The exploitation lore is fun; the boring hygiene is what actually keeps you off the CVE list.
The second thing they get wrong: they think “if it’s a memory-safe language, we’re fine.” You still ship a C dependency somewhere — SQLite, zlib, libpng, OpenSSL, libc itself. Knowing how those fail is part of the job even if your surface code is Rust or Go.
Return to README.md · Next: 04_portability_and_abi.md