<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>coding agents on SecMate Blog</title><link>https://blog.secmate.dev/tags/coding-agents/</link><description>SecMate vulnerability research, technical advisories, security benchmarks, and evidence-backed analysis of exploitable software flaws.</description><generator>Hugo</generator><language>en-us</language><managingEditor>noreply@blog.secmate.dev (SecMate Team)</managingEditor><lastBuildDate>Thu, 17 Sep 2026 12:19:05 +0000</lastBuildDate><atom:link href="https://blog.secmate.dev/tags/coding-agents/index.xml" rel="self" type="application/rss+xml"/><item><title>Which Vulnerabilities Do AI Coding Agents Still Produce?</title><link>https://blog.secmate.dev/posts/ai-generated-cpp-benchmark-gap/</link><pubDate>Thu, 17 Sep 2026 00:00:00 +0200</pubDate><atom:updated>2026-09-17T13:55:30+02:00</atom:updated><dc:creator>Maxime Rossi Bellom</dc:creator><dc:creator>Ramtine Tofighi Shirazi</dc:creator><category>AI Security</category><guid>https://blog.secmate.dev/posts/ai-generated-cpp-benchmark-gap/</guid><description>Why low SQL-injection rates suggest a hypothesis about AI coding agents, what C/C++ benchmarks can tell us, and why strncpy is no security guarantee.</description><content:encoded><![CDATA[<blockquote>
<p><strong>TL;DR:</strong> Coding agents may handle vulnerabilities with established safe coding patterns, such as parameterised queries against SQL injection, better than vulnerabilities requiring contextual reasoning. For C/C++, existing studies do not yet establish a clear shift in vulnerability classes, and apparently safer patterns such as replacing <code>strcpy</code> with <code>strncpy</code> can still leave security defects.</p>
</blockquote>
<p>In our <a href="/posts/vibe-coding-security-benchmark/">August 2025 benchmark</a>, the SecMate team found at least one security issue in 172 of 240 generated samples. We assessed six tasks in C, Java, Python and Rust using <a href="https://secmate.dev?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=ai-generated-cpp-benchmark-gap&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_secmate" data-post-slug="ai-generated-cpp-benchmark-gap" data-post-category="ai-security">SecMate</a>, our source-code security analysis tool, alongside manual review. We have not rerun that benchmark with newer agents.</p>
<h2 id="a-hypothesis-familiar-defences-are-easier-to-apply">A hypothesis: familiar defences are easier to apply</h2>
<p><a href="https://proceedings.mlr.press/v267/vero25a.html" rel="noopener noreferrer" target="_blank">BaxBench</a>, published at ICML 2025, reported SQL-injection occurrence between 0% and 21%, with a median of 0%, across eleven eligible scenarios. Cross-site scripting ranged from 66% to 99% across seven scenarios. These rounded rates apply to functionally correct backends generated without security instructions <a href="#ref1">[1]</a>.</p>
<p>For SQL values, a parameterised query gives the model a recognisable defence to apply at the call site. Correct output encoding depends on where the application inserts a value: HTML text, an attribute and JavaScript do not all use the same escaping rules. Access control requires knowing which user may act on which resource. Choosing an API alone cannot supply that policy.</p>
<p>We suspect this difference helps explain why some classes yield better results than others. These BaxBench results concern language models generating backends, so extending that explanation to repository-level coding agents remains a hypothesis. The rates establish neither a decline in SQL injection over time nor the cause of the difference between classes.</p>
<h2 id="in-cc-safe-looking-code-can-still-violate-security-requirements">In C/C++, safe-looking code can still violate security requirements</h2>
<p>C contains bounded functions that leave part of the security requirement with the caller. Consider this copy:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln">1</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kt">void</span> <span class="nf">set_name</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">dst</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">dst_size</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">src</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nf">strncpy</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="n">dst_size</span><span class="p">);</span>   <span class="cm">/* no NUL when strlen(src) &gt;= dst_size */</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Replacing <code>strcpy</code> with <code>strncpy</code> does not guarantee a secure string copy. The caller must supply the correct destination capacity and ensure that later operations receive a terminated string when they require one.</p>
<p>Assuming valid, non-overlapping buffers and an accurate destination size, <code>strncpy</code> stays within that destination. It produces a terminated string only when the source is shorter than the bound. A later operation that expects a C string may read beyond the unterminated buffer (<a href="https://cwe.mitre.org/data/definitions/170.html" rel="noopener noreferrer" target="_blank">CWE-170</a>) <a href="#ref2">[2]</a>. We documented this termination problem in <a href="/posts/golioth-vulnerabilities-disclosure/#vulnerability-4-coap-blockwise-unterminated-path-out-of-bounds-read-cve-2026-23749-7ref7">Golioth’s CoAP path handling</a>.</p>
<p>With a non-zero destination size, <code>snprintf(dst, dst_size, &quot;%s&quot;, src)</code> produces a terminated result when conversion succeeds and reports truncation through its return value. The caller still needs to supply the correct capacity and decide whether truncation is acceptable.</p>
<p>The <em>Surgical Repair</em> preprint uses <code>strcpy(dst, src)</code> → <code>strncpy(dst, src, n)</code> as one of its safe-pattern substitutions for dataset construction and scoring. The authors acknowledge in Appendix D.1 that <code>strncpy</code> lacks a termination guarantee. Their experiments also show models recognising insecure patterns during review and generating them under prompts that favour other properties, including simplicity or formatting <a href="#ref3">[3]</a>. Learning or recognising a defensive pattern does not ensure that the generated implementation uses it correctly.</p>
<p>Bounds checks can require reasoning even when the code contains no suspicious call. This C++17 helper checks whether an object count can be converted to a byte count without overflow:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;cstddef&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;limits&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">struct</span> <span class="nc">Object</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">payload</span><span class="p">[</span><span class="mi">48</span><span class="p">];</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">size_t</span><span class="o">&gt;</span> <span class="n">object_bytes</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">count</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="k">constexpr</span> <span class="n">std</span><span class="o">::</span><span class="n">size_t</span> <span class="n">width</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Object</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="o">&gt;</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">size_t</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">()</span> <span class="o">/</span> <span class="n">width</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">nullopt</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="k">return</span> <span class="n">count</span> <span class="o">*</span> <span class="n">width</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The required relation is <code>count &lt;= SIZE_MAX / sizeof(Object)</code>. The caller must handle rejection, allocate enough storage, and keep later accesses within it. Our <a href="/posts/slim-bootloader-ext2-group-descriptor-overflow/#from-filesystem-geometry-to-heap-geometry">Slim Bootloader disclosure</a> describes the same class of allocation-size error: integer overflow left insufficient storage for the group descriptor table.</p>
<p>In a repository, input parsing, allocation and access may live in different functions. Ownership bugs unfold over time, races depend on possible interleavings, and protocol bugs depend on legal state transitions. Our <a href="/posts/espressif-usb-cpg-findings/#the-espressif-findings">Espressif USB analysis</a> follows ownership and concurrent cleanup across functions.</p>
<p>These examples and disclosures describe security requirements that implementations must preserve. They do not establish how often agents violate those requirements or whether agents introduced the disclosed defects.</p>
<h2 id="what-cc-studies-establish">What C/C++ studies establish</h2>
<p>Repository-level evaluations show that coding agents still produce memory-safety defects in C and C++ <a href="#ref4">[4]</a> <a href="#ref5">[5]</a>. <a href="https://doi.org/10.1145/3786181.3788703" rel="noopener noreferrer" target="_blank">SecRepoBench</a> contains 318 code-completion tasks from 27 repositories, covering 15 weakness classes. It compiles the repository, runs developer tests, and reuses OSS-Fuzz inputs to check for the target vulnerability. Its evaluation of 29 standalone models and 15 agent configurations finds that agents outperform standalone models on the same tasks <a href="#ref4">[4]</a>. This establishes a benefit from the agent setup within that evaluation; it does not establish a change in the vulnerability distribution over time.</p>
<p><a href="https://aclanthology.org/2026.acl-long.1107/" rel="noopener noreferrer" target="_blank">SecureVibeBench</a> reconstructs 105 vulnerability-introducing tasks from 41 C/C++ projects. Its class-level results complicate our hypothesis: about 10% of generations for heap-based buffer-overflow tasks (CWE-122) are functionally correct but vulnerable, compared with 33% for classic buffer-overflow tasks (CWE-120). Both categories involve memory bounds. Task difficulty, small samples in some classes, and differences between agent frameworks limit what this ordering tells us <a href="#ref5">[5]</a>.</p>
<p>Functional success also leaves security failures unresolved. On SusVibes, SWE-agent with Claude 4 Sonnet passes functionality tests on 57.0% of Python tasks and both functionality and security tests on 11.8%. This configuration has the highest functional success in the reported table; SWE-agent with Gemini 3 Pro has the highest joint success at 12.9% <a href="#ref6">[6]</a>.</p>
<p>On SecureVibeBench, SWE-agent with Claude Sonnet 4.5 reaches 46.7% functional success and 23.8% in the benchmark&rsquo;s correct-and-secure category. That category excludes both confirmed target vulnerabilities and additional static-analysis suspicions. The whole gap therefore cannot be counted as confirmed vulnerabilities <a href="#ref5">[5]</a>.</p>
<figure style="margin:2rem 0;">
<svg viewBox="0 0 800 260" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="gap-title gap-desc" style="width:100%;height:auto;color:inherit;background:transparent;">
  <title id="gap-title">Functional and joint secure success in two repository-level agent benchmarks</title>
  <desc id="gap-desc">SWE-agent with Claude 4 Sonnet on SusVibes achieved 57 percent functional success and 11.8 percent correct-and-secure success. SWE-agent with Claude Sonnet 4.5 on SecureVibeBench achieved 46.7 percent functional success and 23.8 percent correct-and-secure success.</desc>
  <g font-family="system-ui,sans-serif" fill="currentColor">
    <text x="0" y="24" font-size="18" font-weight="700">The functional–security gap</text>
    <text x="0" y="48" font-size="12" opacity=".64">Named configurations within each benchmark; security verdicts differ between studies.</text>
    <g font-size="11" opacity=".58">
      <text x="220" y="84" text-anchor="middle">0%</text>
      <text x="393" y="84" text-anchor="middle">20%</text>
      <text x="567" y="84" text-anchor="middle">40%</text>
      <text x="740" y="84" text-anchor="middle">60%</text>
    </g>
    <g stroke="currentColor" opacity=".14">
      <line x1="220" y1="94" x2="220" y2="220"/>
      <line x1="393" y1="94" x2="393" y2="220"/>
      <line x1="567" y1="94" x2="567" y2="220"/>
      <line x1="740" y1="94" x2="740" y2="220"/>
    </g>
    <text x="0" y="136" font-size="14" font-weight="600">SusVibes</text>
    <text x="0" y="196" font-size="14" font-weight="600">SecureVibeBench</text>
    <line x1="322" y1="130" x2="714" y2="130" stroke="currentColor" stroke-width="2" opacity=".42"/>
    <line x1="426" y1="190" x2="625" y2="190" stroke="currentColor" stroke-width="2" opacity=".42"/>
    <circle cx="714" cy="130" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
    <circle cx="625" cy="190" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
    <circle cx="322" cy="130" r="7"/>
    <circle cx="426" cy="190" r="7"/>
    <g font-size="12">
      <text x="704" y="116" text-anchor="end">functional 57.0%</text>
      <text x="332" y="153">correct + secure 11.8%</text>
      <text x="615" y="176" text-anchor="end">functional 46.7%</text>
      <text x="436" y="213">correct + secure 23.8%</text>
    </g>
  </g>
</svg>
<figcaption style="margin-top:.75rem;font-size:.9rem;opacity:.72;"><strong>Figure 1.</strong> SWE-agent with Claude 4 Sonnet on SusVibes <a href="#ref6">[6]</a>, and SWE-agent with Claude Sonnet 4.5 on SecureVibeBench <a href="#ref5">[5]</a>. SecureVibeBench excludes static-analysis suspicions from its secure category, so its gap includes unconfirmed cases. These are within-study results, not a comparison between models.</figcaption>
</figure>
<p>Neither C/C++ benchmark establishes whether agents improve more on familiar API patterns than on checks that depend on context. Their aggregate scores and class results describe the evaluated tasks and configurations. Publication in 2026 also does not mean every evaluated model was released in 2026.</p>
<h2 id="where-the-evidence-stops">Where the evidence stops</h2>
<p>Deployed applications contain familiar web weaknesses too. Deng, Fan and Meng manually validated 1,471 findings in 200 publicly deployed applications attributed to AI-assisted development. They found broken access control, cryptographic failures, injection and authentication failures <a href="#ref7">[7]</a>. Those observations describe what auditors found in that corpus; they cannot establish which classes agents introduce more or less often than human developers.</p>
<table>
<thead>
<tr>
<th>Evidence</th>
<th>What it supports</th>
<th>What remains unknown</th>
</tr>
</thead>
<tbody>
<tr>
<td>BaxBench&rsquo;s SQL-injection and XSS results</td>
<td>Classes have different failure rates within this evaluation.</td>
<td>Whether familiar defences explain the difference, or SQL injection is declining.</td>
</tr>
<tr>
<td>C/C++ repository benchmarks</td>
<td>Agents still generate memory-safety defects; outcomes vary by task and agent setup.</td>
<td>Whether the class distribution is shifting across agent generations.</td>
</tr>
<tr>
<td>Pattern-based scoring in <em>Surgical Repair</em></td>
<td>API choices can be measured under the study&rsquo;s prompt conditions.</td>
<td>Whether a recognised pattern satisfies the full security requirement.</td>
</tr>
<tr>
<td>Audits of deployed AI-attributed applications</td>
<td>Access-control, injection, cryptographic and authentication flaws occur in this corpus.</td>
<td>Their prevalence relative to comparable human-written applications; attribution and audit coverage are also uncertain.</td>
</tr>
</tbody>
</table>
<p>To test our hypothesis over time, we would need stable tasks and prompts across agent versions, enough opportunities for each weakness class, and the same functional and security checks for every version. Rerunning our 2025 benchmark and rescoring both sets of samples with those checks would provide a starting point. Broader C/C++ coverage would still be needed for ownership, concurrency and state-dependent failures.</p>
<h2 id="what-to-check-in-generated-code">What to check in generated code</h2>
<p>When reviewing generated code, check the conditions around each defensive pattern:</p>
<ul>
<li>For SQL queries, verify that untrusted values use parameters and review any dynamically constructed query structure.</li>
<li>For bounded string operations, check the actual capacity, termination and handling of truncation.</li>
<li>For allocations, follow sizes from input through arithmetic to allocation and later access. Check how callers handle rejected sizes.</li>
<li>For ownership and state, follow cleanup paths, concurrent access and legal transitions across functions.</li>
</ul>
<p>Use security tests to exercise these requirements alongside functional tests. For <code>strncpy</code>, verify that every later use requiring a terminated string receives one.</p>
<p><a href="https://secmate.dev?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=ai-generated-cpp-benchmark-gap&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_secmate" data-post-slug="ai-generated-cpp-benchmark-gap" data-post-category="ai-security">SecMate</a> uses program analysis to collect the calls, conditions and data relationships relevant to a suspected vulnerability. In our Espressif USB work, we used that evidence to investigate bounds, lifetime and concurrency defects. Researchers validated the findings before disclosure.</p>
<h2 id="references">References</h2>
<section class="post-references" aria-labelledby="references">
  <ol class="post-references-list">
    <li id="ref1"><a href="https://proceedings.mlr.press/v267/vero25a.html" rel="noopener noreferrer" target="_blank">Vero et al. “BaxBench: Can LLMs Generate Correct and Secure Backends?” ICML 2025.</a></li>
    <li id="ref2"><a href="https://cwe.mitre.org/data/definitions/170.html" rel="noopener noreferrer" target="_blank">MITRE. “CWE-170: Improper Null Termination.”</a></li>
    <li id="ref3"><a href="https://arxiv.org/abs/2604.16697" rel="noopener noreferrer" target="_blank">Sandoval, Dolan-Gavitt, and Garg. “Surgical Repair of Insecure Code Generation in LLMs.” Academic preprint, 2026.</a></li>
    <li id="ref4"><a href="https://doi.org/10.1145/3786181.3788703" rel="noopener noreferrer" target="_blank">Shen et al. “SecRepoBench: Benchmarking Code Agents for Secure Code Completion in Real-World Repositories.” LLM4Code 2026.</a></li>
    <li id="ref5"><a href="https://aclanthology.org/2026.acl-long.1107/" rel="noopener noreferrer" target="_blank">Chen et al. “SecureVibeBench: Benchmarking Secure Vibe Coding of AI Agents via Reconstructing Vulnerability-Introducing Scenarios.” ACL 2026.</a></li>
    <li id="ref6"><a href="https://arxiv.org/abs/2512.03262" rel="noopener noreferrer" target="_blank">Zhao et al. “Is Vibe Coding Safe? Benchmarking Vulnerability of Agent-Generated Code in Real-World Tasks.” Accepted at ICML 2026; preprint revised August 2026.</a></li>
    <li id="ref7"><a href="https://arxiv.org/abs/2606.23130v2" rel="noopener noreferrer" target="_blank">Deng, Fan, and Meng. “Understanding the (In)Security of Vibe-Coded Applications.” Academic preprint, version 2, June 23, 2026.</a></li>
  </ol>
</section>
<hr>
<p><em>The SecMate Team</em></p>
]]></content:encoded><media:content url="https://blog.secmate.dev/images/og_image.jpg" medium="image"/></item></channel></rss>