<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Rust on guy@secdev.uk</title>
    <link>https://www.secdev.uk/blog/tags/rust/</link>
    <description>Recent content in Rust on guy@secdev.uk</description>
    <generator>Hugo</generator>
    <language>en-gb</language>
    <copyright>Guy Dixon | guy@secdev.uk</copyright>
    <lastBuildDate>Sat, 04 Apr 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.secdev.uk/blog/tags/rust/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Rust Security Code Review Guide</title>
      <link>https://www.secdev.uk/blog/articles/rust_security_review_guide/</link>
      <pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/articles/rust_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 Rust applications. Whether you&amp;rsquo;re just starting to identify security vulnerabilities in Rust 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;Rust&amp;rsquo;s ownership model, borrow checker, and type system prevent entire classes of bugs, use-after-free, null pointer dereferences, and data races in safe code. However, what I found when I started reviewing Rust codebases is that &lt;code&gt;unsafe&lt;/code&gt; blocks, third-party crate choices, and application-level logic errors still introduce serious vulnerabilities. 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>Rust Learning Guide - Anti-Patterns</title>
      <link>https://www.secdev.uk/blog/articles/rust_antipatterns/</link>
      <pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/articles/rust_antipatterns/</guid>
      <description>&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;antipatterns.rs&lt;/code&gt; module &lt;a href=&#34;https://github.com/guyadixon/RustLearning/blob/main/src/antipatterns.rs&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&#xA;    Source Code File&#xA;&lt;/a&gt;&#xA; demonstrates 15 common Rust mistakes and their correct solutions. I put this together because I noticed the same patterns coming up, especially from developers (myself included) fighting the borrow checker instead of working with it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;anti-patterns-covered&#34;&gt;Anti-Patterns Covered&lt;/h2&gt;&#xA;&lt;h3 id=&#34;1-unnecessary-clone-everywhere&#34;&gt;1. &lt;strong&gt;Unnecessary .clone() Everywhere&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Cloning to avoid borrow checker&lt;/li&gt;&#xA;&lt;li&gt;✅ Use references (&amp;amp;T) instead&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;2-using-unwrap-in-production&#34;&gt;2. &lt;strong&gt;Using .unwrap() in Production&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Crashes program on error&lt;/li&gt;&#xA;&lt;li&gt;✅ Return Result&amp;lt;T, E&amp;gt; and handle gracefully&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;3-returning-references-to-local-variables&#34;&gt;3. &lt;strong&gt;Returning References to Local Variables&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Dangling references (won&amp;rsquo;t compile)&lt;/li&gt;&#xA;&lt;li&gt;✅ Return owned data or use &amp;lsquo;static lifetime&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;4-using-string-when-str-would-work&#34;&gt;4. &lt;strong&gt;Using String When &amp;amp;str Would Work&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Forces caller to own String&lt;/li&gt;&#xA;&lt;li&gt;✅ Accept &amp;amp;str - works with both&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;5-ignoring-compiler-warnings&#34;&gt;5. &lt;strong&gt;Ignoring Compiler Warnings&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Unused mut, unused variables&lt;/li&gt;&#xA;&lt;li&gt;✅ Listen to the compiler&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;6-using-indices-instead-of-iterators&#34;&gt;6. &lt;strong&gt;Using Indices Instead of Iterators&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ C-style loops can panic&lt;/li&gt;&#xA;&lt;li&gt;✅ Use iterators - safer and clearer&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;7-manually-implementing-what-traits-provide&#34;&gt;7. &lt;strong&gt;Manually Implementing What Traits Provide&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Manual equality checks&lt;/li&gt;&#xA;&lt;li&gt;✅ #[derive(PartialEq, Debug, Clone)]&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;8-using-vec-when-array-would-work&#34;&gt;8. &lt;strong&gt;Using Vec When Array Would Work&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Heap allocation for fixed-size data&lt;/li&gt;&#xA;&lt;li&gt;✅ Use arrays [T; N] for stack allocation&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;9-nested-matchif-let-instead-of-combinators&#34;&gt;9. &lt;strong&gt;Nested match/if let Instead of Combinators&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Deeply nested matching&lt;/li&gt;&#xA;&lt;li&gt;✅ Use .map(), .filter(), .and_then()&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;10-using-mutex-when-not-needed&#34;&gt;10. &lt;strong&gt;Using Mutex When Not Needed&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Mutex in single-threaded code&lt;/li&gt;&#xA;&lt;li&gt;✅ Just use regular variables&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;11-collecting-iterator-just-to-iterate-again&#34;&gt;11. &lt;strong&gt;Collecting Iterator Just to Iterate Again&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Unnecessary intermediate collection&lt;/li&gt;&#xA;&lt;li&gt;✅ Chain iterators directly&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;12-using-deref-coercion-as-inheritance&#34;&gt;12. &lt;strong&gt;Using Deref Coercion as Inheritance&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Simulating inheritance with Deref&lt;/li&gt;&#xA;&lt;li&gt;✅ Use composition explicitly&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;13-panicking-in-library-code&#34;&gt;13. &lt;strong&gt;Panicking in Library Code&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ panic!() crashes caller&amp;rsquo;s program&lt;/li&gt;&#xA;&lt;li&gt;✅ Return Result and let caller decide&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;14-using-format-when-to_&#34;&gt;14. &lt;strong&gt;Using format! When to_string() Works&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Overkill for simple conversions&lt;/li&gt;&#xA;&lt;li&gt;✅ Use .to_string() for clarity&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;15-implementing-default-manually&#34;&gt;15. &lt;strong&gt;Implementing Default Manually&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;❌ Manual new() constructor&lt;/li&gt;&#xA;&lt;li&gt;✅ Implement Default trait&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;key-principle&#34;&gt;Key Principle&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Work WITH Rust&amp;rsquo;s ownership system, not against it.&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rust Learning Guide - Core Concepts Explained</title>
      <link>https://www.secdev.uk/blog/articles/rust_learning_guide/</link>
      <pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/articles/rust_learning_guide/</guid>
      <description>&lt;p&gt;I put this guide together to explain each Rust concept demonstrated in the example programs, with comparisons to C and Java. The more I dug into Rust&amp;rsquo;s design decisions, the more I appreciated how much thought went into making safety guarantees that don&amp;rsquo;t cost you performance. Here&amp;rsquo;s what I found.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/guyadixon/RustLearning&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&#xA;    Supporting Code Examples&#xA;&lt;/a&gt;&#xA;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-ownership-system&#34;&gt;1. OWNERSHIP SYSTEM&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Rust&amp;rsquo;s core memory management system. Every value has a single owner, and when the owner goes out of scope, the value is dropped (freed). This was the concept that took the longest to click for me, but once it did, everything else fell into place.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rust Security: When unsafe Breaks the Promise</title>
      <link>https://www.secdev.uk/blog/technology/2025-10-11-rust-security-unsafe-breaks-promise/</link>
      <pubDate>Sat, 11 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-10-11-rust-security-unsafe-breaks-promise/</guid>
      <description>&lt;p&gt;I love Rust. I genuinely do. Its ownership system, borrow checker, and type system wipe out entire classes of vulnerabilities at compile time, use-after-free, double-free, data races, null pointer dereferences, buffer overflows. But here&amp;rsquo;s the thing: Rust gives you an escape hatch called &lt;code&gt;unsafe&lt;/code&gt;, and when it&amp;rsquo;s used incorrectly, it reintroduces every single vulnerability that Rust was designed to prevent. The more I dug into real-world Rust codebases, the more I found this happening. Beyond &lt;code&gt;unsafe&lt;/code&gt;, Rust has its own quirky set of security pitfalls: integer overflow behaviour that differs between debug and release builds, FFI boundaries that trust C code unconditionally, and logic errors that the type system simply cannot catch. In this post, I want to walk through the Rust-specific anti-patterns that break the safety promise.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Race Conditions</title>
      <link>https://www.secdev.uk/blog/technology/2025-08-16-race-conditions/</link>
      <pubDate>Sat, 16 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-08-16-race-conditions/</guid>
      <description>&lt;p&gt;Race conditions (CWE-362) are, in my opinion, the most insidious class of security bugs you&amp;rsquo;ll encounter. They occur when the behaviour of a program depends on the relative timing of concurrent operations, and at least one of those operations modifies shared state. The window between a check and a subsequent use of the checked value, the classic time-of-check to time-of-use (TOCTOU) pattern, is the most exploited form, but races also show up in counter increments, balance updates, session management, and file operations. What makes race conditions uniquely dangerous is their non-determinism: the bug may not manifest in thousands of test runs, then appear under production load when two requests arrive within microseconds of each other. I want to walk through race conditions in Python, Go, Java, and Rust, from the obvious unprotected counter to the subtle channel-based ordering assumption that passes every test but fails under contention.&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>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>Authentication Failures</title>
      <link>https://www.secdev.uk/blog/technology/2025-04-26-authentication-failures/</link>
      <pubDate>Sat, 26 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-04-26-authentication-failures/</guid>
      <description>&lt;p&gt;Authentication is the front door of every application, and OWASP A07 documents how often that door is left unlocked. When I started digging into authentication failures, I realised they go far beyond weak passwords, they encompass hardcoded credentials compiled into binaries, brute-force attacks with no rate limiting, password hashes that can be reversed in seconds, and reset flows that hand tokens directly to attackers. These patterns show up in production regularly, sometimes in the same application. This post covers three CWEs across Python, Java, Go, and Rust: CWE-798 (Use of Hard-Coded Credentials), CWE-287 (Improper Authentication), and CWE-307 (Improper Restriction of Excessive Authentication Attempts).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cryptographic Failures That Pass Code Review</title>
      <link>https://www.secdev.uk/blog/technology/2025-03-01-cryptographic-failures-that-pass-code-review/</link>
      <pubDate>Sat, 01 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-03-01-cryptographic-failures-that-pass-code-review/</guid>
      <description>&lt;p&gt;Cryptographic code is uniquely dangerous, and it&amp;rsquo;s one of the areas I find most challenging to review. The reason is simple: it can be completely wrong and still appear to work perfectly. A broken hash function still produces a hash. A weak cipher still encrypts and decrypts. A predictable random number generator still generates numbers. The application runs, tests pass, and the vulnerability sits quietly until an attacker exploits it. In this post, I want to walk through the cryptographic failures that routinely survive code review across Python, Java, Go, and Rust, from the obvious use of MD5 to the subtle misuse of otherwise strong primitives.&lt;/p&gt;</description>
    </item>
    <item>
      <title>XSS Is Not Just a JavaScript Problem</title>
      <link>https://www.secdev.uk/blog/technology/2025-02-01-xss-is-not-just-a-javascript-problem/</link>
      <pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://www.secdev.uk/blog/technology/2025-02-01-xss-is-not-just-a-javascript-problem/</guid>
      <description>&lt;p&gt;Cross-site scripting gets framed as a front-end problem a lot, something that happens in JavaScript and gets fixed with JavaScript. But the more I dug into this, the clearer it became that XSS vulnerabilities almost always originate on the server side, in whatever language is generating the HTML. I&amp;rsquo;ve found XSS in Python templates, Java JSPs, Go&amp;rsquo;s &lt;code&gt;html/template&lt;/code&gt; misuse, Rust web frameworks, and server-rendered JavaScript. The language you write your backend in determines which XSS patterns you&amp;rsquo;ll run into and which ones will sneak past your review.&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>
