<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>C on guy@secdev.uk</title>
    <link>https://www.secdev.uk/blog/tags/c/</link>
    <description>Recent content in C on guy@secdev.uk</description>
    <generator>Hugo</generator>
    <language>en-gb</language>
    <copyright>Guy Dixon | guy@secdev.uk</copyright>
    <lastBuildDate>Sat, 14 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.secdev.uk/blog/tags/c/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Memory Safety Without Rust: Defensive C and C&#43;&#43; Patterns</title>
      <link>https://www.secdev.uk/blog/technology/2026-03-14-memory-safety-without-rust/</link>
      <pubDate>Sat, 14 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2026-03-14-memory-safety-without-rust/</guid>
      <description>&lt;p&gt;I hear &amp;ldquo;just rewrite it in Rust&amp;rdquo; a lot these days, and while Rust&amp;rsquo;s ownership model genuinely does eliminate entire classes of memory safety bugs at compile time, that advice ignores reality. The vast majority of systems code &amp;ndash; operating systems, embedded firmware, database engines, network stacks &amp;ndash; is written in C and C++ and will remain so for decades. Rewriting is not always an option. So I wanted to dig into the defensive patterns, compiler features, and runtime tools that bring memory safety closer to C and C++ codebases without a language migration. What I found is that while none of these approaches match Rust&amp;rsquo;s compile-time guarantees, the combination of them makes a real difference.&lt;/p&gt;</description>
    </item>
    <item>
      <title>XXE Attacks: XML Parsing Gone Wrong</title>
      <link>https://www.secdev.uk/blog/technology/2026-01-31-xxe-attacks/</link>
      <pubDate>Sat, 31 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2026-01-31-xxe-attacks/</guid>
      <description>&lt;p&gt;XML External Entity injection is one of those vulnerabilities that fascinated me the more I dug into it. The core issue is that the XML spec supports external entities, a feature that lets XML documents pull in content from external sources, and most parsers enable this by default. When an app parses untrusted XML without disabling that feature, an attacker can read arbitrary files off the server, perform SSRF, and sometimes even get remote code execution. What surprised me most when researching this was how straightforward the exploitation is compared to how long these bugs survive in production, the attack payloads are simple, but the parser defaults are so permissive that developers often have no idea the risk exists.&lt;/p&gt;</description>
    </item>
    <item>
      <title>String Formatting and Security: A Cross-Language Minefield</title>
      <link>https://www.secdev.uk/blog/technology/2026-01-03-string-formatting-and-security/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2026-01-03-string-formatting-and-security/</guid>
      <description>&lt;p&gt;String formatting is one of those operations that&amp;rsquo;s everywhere, and it&amp;rsquo;s more dangerous than most developers realise when user input gets involved. Every language provides multiple ways to build strings from dynamic data, and each mechanism carries different security implications. From C&amp;rsquo;s &lt;code&gt;printf&lt;/code&gt; family, where a format string bug can read and write arbitrary memory, to Python&amp;rsquo;s f-strings that can execute attribute lookups, the attack surface is broader than most people think. I wanted to map out the full landscape across languages, and what I found was that each mechanism breaks down in its own unique and sometimes surprising way.&lt;/p&gt;</description>
    </item>
    <item>
      <title>SAST Tools Compared: What They Catch and What They Miss</title>
      <link>https://www.secdev.uk/blog/technology/2025-12-20-sast-tools-compared/</link>
      <pubDate>Sat, 20 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-12-20-sast-tools-compared/</guid>
      <description>&lt;p&gt;Static Application Security Testing (SAST) tools are the first line of automated defence against vulnerabilities in source code. They analyse code without executing it, looking for patterns that match known vulnerability classes. But here&amp;rsquo;s the thing, no single tool catches everything, and the differences between tools in detection capability, false positive rates, and language support are significant. I wanted to understand exactly where the gaps are, so I spent time running these tools against intentionally vulnerable code and comparing their output. This post is my honest assessment of what they actually catch, what they miss, and where manual review has to pick up the slack.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Art of the Subtle Bug: Nuanced Vulnerabilities That Evade Review</title>
      <link>https://www.secdev.uk/blog/technology/2025-12-06-the-art-of-the-subtle-bug/</link>
      <pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-12-06-the-art-of-the-subtle-bug/</guid>
      <description>&lt;p&gt;The vulnerabilities that cause real breaches are rarely the textbook examples. They&amp;rsquo;re the ones that survive multiple rounds of code review, pass SAST scans, and sit in production for years. The more I researched these nuanced bugs, the more I realised what makes them dangerous: they exploit assumptions reviewers make about language behaviour, framework internals, or data flow boundaries. This post dissects the patterns that make a vulnerability subtle and walks through real examples that show why even experienced reviewers still miss them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>C Security: Manual Memory Management and Its Consequences</title>
      <link>https://www.secdev.uk/blog/technology/2025-10-25-c-security-manual-memory-management/</link>
      <pubDate>Sat, 25 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-10-25-c-security-manual-memory-management/</guid>
      <description>&lt;p&gt;C gives you direct control over memory allocation, pointer arithmetic, and hardware interaction. I respect that. But that control comes with absolutely no safety net: no bounds checking, no garbage collection, no type safety beyond what you enforce manually. Every buffer overflow, use-after-free, double-free, format string vulnerability, and null pointer dereference in C is a direct consequence of this design. C remains the language of operating systems, embedded systems, and performance-critical libraries, so its security pitfalls affect every layer of the software stack. When I started digging into the patterns behind C vulnerabilities, the same shapes kept appearing, from the textbook &lt;code&gt;strcpy&lt;/code&gt; overflow to the subtle integer promotion that bypasses a bounds check. Let me walk through them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Integer Overflow</title>
      <link>https://www.secdev.uk/blog/technology/2025-08-02-integer-overflow/</link>
      <pubDate>Sat, 02 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-08-02-integer-overflow/</guid>
      <description>&lt;p&gt;Integer overflow (CWE-190) is one of those bugs that I find endlessly fascinating because of how quietly destructive it is. It happens when an arithmetic operation produces a value that exceeds the maximum (or falls below the minimum) representable value for the integer type. In C and C++, signed integer overflow is undefined behaviour, the compiler is free to assume it never happens, and optimizations built on that assumption can eliminate bounds checks entirely. Unsigned overflow wraps around silently. Go and Java define overflow as wrapping (two&amp;rsquo;s complement), which prevents undefined behaviour but still produces incorrect results that lead to security vulnerabilities: undersized allocations, bypassed length checks, and negative indices into arrays. Rust panics on overflow in debug mode but wraps in release mode by default, creating a gap between testing and production behaviour that caught me off guard when I first started digging into Rust&amp;rsquo;s safety guarantees. I want to walk through integer overflow across C, C++, Rust, Go, and Java, from the textbook multiplication overflow to the subtle cast truncation that can survive expert review.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Null Pointer Dereference</title>
      <link>https://www.secdev.uk/blog/technology/2025-07-19-null-pointer-dereference/</link>
      <pubDate>Sat, 19 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-07-19-null-pointer-dereference/</guid>
      <description>&lt;p&gt;Null pointer dereference (CWE-476) is one of those bugs that shows up across every language, and the more I researched it for this post, the more I was struck by how much damage it can do depending on context. The consequences vary dramatically: C programs crash with a segfault (or worse, the kernel maps page zero and an attacker gets code execution), C++ invokes undefined behaviour that the compiler may optimise into literally anything, Go panics with a nil pointer dereference that kills the goroutine or the whole program, and Java throws a &lt;code&gt;NullPointerException&lt;/code&gt; that can crash the app or leak stack traces to an attacker. MITRE ranks CWE-476 consistently in the top 25 most dangerous software weaknesses, and digging into the CVE data, that ranking is well deserved. I want to walk through C, C++, Go, and Java here, from the obvious unchecked &lt;code&gt;malloc&lt;/code&gt; return to the subtle nil interface trap in Go and the conditional path where null silently propagates through multiple function calls.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Use After Free</title>
      <link>https://www.secdev.uk/blog/technology/2025-07-05-use-after-free/</link>
      <pubDate>Sat, 05 Jul 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-07-05-use-after-free/</guid>
      <description>&lt;p&gt;Use-after-free (CWE-416) is one of those bug classes that I wanted to understand deeply because it keeps showing up at the root of high-profile exploits. It occurs when a program continues to use a pointer after the memory it references has been freed. The freed memory may be reallocated for a different purpose, and the dangling pointer now reads or writes data that belongs to a completely different object. Attackers exploit this by controlling what gets allocated into the freed slot, replacing a data buffer with a crafted object that contains a function pointer, then triggering the dangling pointer to call through it. Reading through CVE databases, use-after-free is at the root of hundreds of browser exploits, kernel privilege escalations, and server compromises. This post covers C and C++, from the obvious free-then-use to the subtle shared-pointer aliasing and callback registration patterns that can evade expert review.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Out-of-Bounds Writes</title>
      <link>https://www.secdev.uk/blog/technology/2025-06-21-out-of-bounds-writes/</link>
      <pubDate>Sat, 21 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-06-21-out-of-bounds-writes/</guid>
      <description>&lt;p&gt;Out-of-bounds writes (CWE-787) are the single most dangerous class of memory corruption vulnerabilities on the SANS/CWE Top 25, and they&amp;rsquo;ve held that position for years. The reason is clear once you dig into the mechanics: writing past the end of a buffer can overwrite return addresses, function pointers, vtable entries, and adjacent heap metadata, giving attackers arbitrary code execution. Unlike higher-level languages where the runtime catches array index violations, C and C++ silently corrupt memory, and the consequences may not manifest until thousands of instructions later. Even Rust, with its ownership model, is vulnerable when &lt;code&gt;unsafe&lt;/code&gt; blocks bypass the borrow checker. In this post I&amp;rsquo;ll dissect out-of-bounds writes in C, C++, and Rust, from the classic &lt;code&gt;strcpy&lt;/code&gt; overflow to the subtle off-by-one in pointer arithmetic that can survive expert review.&lt;/p&gt;</description>
    </item>
    <item>
      <title>C Security Code Review Guide</title>
      <link>https://www.secdev.uk/blog/articles/c_security_review_guide/</link>
      <pubDate>Tue, 04 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/articles/c_security_review_guide/</guid>
      <description>&lt;h2 id=&#34;1-introduction&#34;&gt;1. Introduction&lt;/h2&gt;&#xA;&lt;p&gt;I put this guide together as a structured approach to security-focused code review for C applications. Whether you&amp;rsquo;re just starting to identify security vulnerabilities in C code or you&amp;rsquo;re an experienced developer looking for a language-specific checklist, I&amp;rsquo;ve tried to make it useful at both levels.&lt;/p&gt;&#xA;&lt;p&gt;C&amp;rsquo;s manual memory management, lack of bounds checking, direct pointer arithmetic, and minimal runtime safety make it uniquely prone to entire classes of vulnerabilities that higher-level languages prevent by design. The more I dug into C codebases, the more I appreciated just how many ways things can go wrong, buffer overflows, use-after-free, null pointer dereferences, integer overflows, and format string attacks are all first-class concerns. What follows covers manual review strategies, common anti-patterns, recommended tooling, and vulnerability patterns organised by class, with cross-references to the intentionally vulnerable examples in this project.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Command Injection Beyond os.system</title>
      <link>https://www.secdev.uk/blog/technology/2025-01-18-command-injection-beyond-os-system/</link>
      <pubDate>Sat, 18 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-01-18-command-injection-beyond-os-system/</guid>
      <description>&lt;p&gt;When most developers hear &amp;ldquo;command injection,&amp;rdquo; they think of &lt;code&gt;os.system()&lt;/code&gt; in Python or &lt;code&gt;Runtime.exec()&lt;/code&gt; in Java. Those are the textbook examples, and most teams know to avoid them. But the more I researched this topic, the more I realised that command injection surfaces through dozens of less obvious APIs across every language, subprocess pipes, shell expansions, backtick operators, and even seemingly safe exec functions that become dangerous with the wrong arguments. This is one of my favourite vulnerability classes to dig into because the attack surface is so much wider than people realise. Let me walk you through command injection patterns across seven languages, from the obvious to the genuinely subtle.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
