<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Duru Victor]]></title><description><![CDATA[Duru Victor]]></description><link>https://iamduruvictor.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a49bb6aa26852f4982a81dd/5c667e16-54d2-4f78-9ce5-c3a2dd320148.jpg</url><title>Duru Victor</title><link>https://iamduruvictor.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 25 Sep 2026 23:04:25 GMT</lastBuildDate><atom:link href="https://iamduruvictor.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I Tried to Break My Own C Program, And Found a Real Bug Hiding in the Input Buffer]]></title><description><![CDATA[Intro
This was me building a mini project (time converter) after finishing chapter 5 of C Programming: A Modern Approach by K.N. King. I decided to test the program by feeding it input that looked lik]]></description><link>https://iamduruvictor.hashnode.dev/i-tried-to-break-my-own-c-program-and-found-a-real-bug-hiding-in-the-input-buffer</link><guid isPermaLink="true">https://iamduruvictor.hashnode.dev/i-tried-to-break-my-own-c-program-and-found-a-real-bug-hiding-in-the-input-buffer</guid><category><![CDATA[C]]></category><category><![CDATA[Security]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[cybersecurity]]></category><dc:creator><![CDATA[Duru Victor Ikechukwu]]></dc:creator><pubDate>Wed, 05 Aug 2026 03:17:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/5081b440-e7d7-4b88-abcb-b15a1e0940c9.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Intro</h2>
<p>This was me building a mini project (time converter) after finishing chapter 5 of C Programming: A Modern Approach by K.N. King. I decided to test the program by feeding it input that looked like a valid time range and format but wasn't. Instead of catching it, the program read it successfully and confidently printed a normal-looking, seemingly valid result, even though the input should have been rejected.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/ca5903c0-97d5-43bd-b305-4ae16bfe8a09.jpg" alt="" style="display:block;margin:0 auto" />

<p>[ Full code and PoC on GitHub] (<a href="https://github.com/iamduruvictor/scanf-buffer-leftover-bug">https://github.com/iamduruvictor/scanf-buffer-leftover-bug</a>)</p>
<h2>What I noticed</h2>
<p>By default, I built in two checks: one for correct time format, and one for correct time range.</p>
<pre><code class="language-c">if (result != 2) {
    printf("Invalid Time format.\n");
    return 1;
   }
</code></pre>
<pre><code class="language-cpp">if (hour &gt; 23 || hour &lt; 0 || mintues &gt; 59 || mintues &lt; 0) {
    printf("Invalid Time range.\n");
    return 1;
   }
</code></pre>
<p>Whilst testing the program, the snippets successfully caught bad inputs and displayed the right error messages.</p>
<p>Incorrect time format:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/937ca8cb-6685-4b3b-9a8d-cd835ab5cf74.png" alt="" style="display:block;margin:0 auto" />

<p>Incorrect time range:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/13504f8a-a8c8-4383-83c4-463f39388287.png" alt="" style="display:block;margin:0 auto" />

<p>Then I tried something different. I gave it a valid-looking two-digit hour and minute value, but added extra digits after them. To my surprise, scanf accepted the input and the program printed a normal-looking result, as if nothing was wrong, even though what I typed was clearly invalid.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/b2779fdf-12d8-4633-bb42-0f8e9cea4899.png" alt="" style="display:block;margin:0 auto" />

<p>This violates the code <em>“Minutes &gt; 59”</em> because of the way I wrote it.</p>
<h2>My hypothesis</h2>
<p>Since scanf read the input without an error, printed the program successfully, and the extra digits I typed never showed up anywhere in the output, I knew something didn't add up. Based on my knowledge from earlier reading—<em>about inputs being held in a (stdin) buffer before a program reads it</em>, I then began to suspect that the leftover digits hadn't disappeared. They were still sitting in the buffer, waiting for the next scanf call to execute.</p>
<h2>Testing it: the PoC</h2>
<p>To test that hypothesis, I added a second scanf call after the program's normal logic since my assumption suggests that the leftover value would be sitting somewhere in the stdin buffer.</p>
<pre><code class="language-c">int attack;
  scanf("%d", &amp;attack);
  printf("\nBuffer Leftover: %d", attack);
</code></pre>
<p>I declared a variable called attack (the name was mostly for fun, but it stuck), used scanf to read into it, expecting it would either wait for fresh input from me or, if my hypothesis was right, silently pick up whatever was still sitting in the buffer instead. Then paired it with a printf call to output exactly what got read (i.e what was passed into the variable ‘attack’).</p>
<h2>What's actually happening</h2>
<p>The program only accepts 2 digits per field (%2d), backed by a format check and a range check, hours between 0–23, minutes between 0–59. Feeding a clearly invalid 3-digit hour or an out-of-range minute (like 60) correctly triggered the error messages, as expected. But this trick worked differently: %2d only ever reads the first 2 digits of whatever I typed, it doesn't care if more digits follow. So it happily read the valid-looking first 2 digits, and the extra digit(s) I typed were left completely untouched in the input buffer.</p>
<p>When I ran the program with my added PoC, the second scanf call didn't wait for me to type anything. It executed itself using the leftover digit(s) still sitting in the buffer from my first input. No new keystroke required, and the printf function call right after it proved it, printing the exact leftover value back to me.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/c3688efe-18eb-4261-87a6-01415a89edff.png" alt="" style="display:block;margin:0 auto" />

<p>Another trial:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a49bb6aa26852f4982a81dd/b380a3b8-a66a-465b-9287-0f5e0d7b9430.png" alt="" style="display:block;margin:0 auto" />

<h2>Why it matters</h2>
<p>This is a real instance of a well-known weakness pattern CWE-20, Improper Input Validation. In my program, the consequence is harmless: wrong-looking output on my own screen, nothing more. That's an important distinction.</p>
<p>A bug is any unintended behavior; it only becomes a vulnerability once it can be leveraged to actually violate a system's security, whether that's letting someone see data they shouldn't, change something they shouldn't, or break availability. But the same underlying pattern; unvalidated input leaving unexpected data behind for a later read to silently consume, is exactly the kind of weakness that becomes dangerous once it touches something security-relevant: a buffer size calculation, an array index, an authentication check.</p>
<p>The difference between "quirky bug" and "real vulnerability" isn't the mechanism, it's what that leftover data ends up touching downstream.</p>
<h2>What I'm taking from this</h2>
<p>This taught me that testing a program only within the boundaries you expect isn't enough. The real test is trying to break it from outside those boundaries, deliberately, and seeing what it gives.</p>
<p>This class of bug isn't unique to C. Buffer-related input quirks show up in higher-level languages too (Java's Scanner has a well-documented version of this exact problem). But it's more dangerous specifically in C and C++, because these languages don't manage memory or clean up automatically after use. In a higher-level language, leftover input usually just causes a harmless error. In C, if a value goes unread or a variable goes uninitialized as a result, you're dealing with a real memory-safety problem, not just a logic slip.</p>
<p>As someone building toward vulnerability research and exploit development, this confirmed something I'd heard before but hadn't really felt for myself yet: “one of the best places to find real vulnerabilities in a system is by tracing the code all the way back to where it requires a user input.”</p>
]]></content:encoded></item></channel></rss>