<?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>code review on SecMate Blog</title><link>https://blog.secmate.dev/tags/code-review/</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, 29 Oct 2026 08:25:39 +0000</lastBuildDate><atom:link href="https://blog.secmate.dev/tags/code-review/index.xml" rel="self" type="application/rss+xml"/><item><title>Find Vulnerabilities with AI. Keep Your Code Private.</title><link>https://blog.secmate.dev/posts/local-airgapped-security-review/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0100</pubDate><atom:updated>2026-10-28T15:48:31+01: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/local-airgapped-security-review/</guid><description>Run AI security code reviews on your own infrastructure. See SecMate's disclosed vulnerabilities and a local-model comparison on NVIDIA DGX Spark.</description><content:encoded><![CDATA[<p>Product security teams need to investigate suspicious code, validate findings and review changes before release. When source code cannot leave the organization, that work has to run on infrastructure the team controls.</p>
<p>Locally deployable models have already produced reportable vulnerabilities. In our <a href="/posts/optee-vulnerabilities-disclosure/">OP-TEE research</a>, GPT-OSS models found three memory-corruption issues in the privileged core; two received CVEs. Those findings came from investigating software used to isolate sensitive code and data from the normal operating system.</p>
<p>For teams evaluating local AI security review, the practical questions are what hardware it requires, which tools produce useful findings, and how long reviews take. We compared SecMate, OpenCode and Arm Metis on five known vulnerabilities, using the same DeepSeek Flash model served from a single NVIDIA DGX Spark. A first evaluation does not require a six-figure GPU cluster.</p>
<h2 id="hardware-and-local-setup">Hardware and local setup</h2>
<p>Our Spark has 128 GB of shared CPU and GPU memory.</p>
<p><a href="https://docs.ollama.com/api/openai-compatibility" rel="noopener noreferrer" target="_blank">Ollama</a> and <a href="https://docs.vllm.ai/en/latest/serving/online_serving/" rel="noopener noreferrer" target="_blank">vLLM</a> can expose local models through an OpenAI-compatible API. Our DeepSeek Flash checkpoint needs the <a href="https://github.com/0xSero/deepseek-v4-flash-0731-spark-sparkinfer" rel="noopener noreferrer" target="_blank">adapted vLLM and SparkInfer Docker stack</a>. Its published recipe handles loading the model and the Spark&rsquo;s GPU kernels.</p>
<p>The review harness chooses files, calls the model and checks suspected bugs. It can run on the Spark or on another machine, such as a virtual machine on the same private network.</p>
<figure style="margin: 1.5rem 0;">
<div style="display: flex; flex-wrap: wrap; gap: 20px; color: var(--color-text, #334155); font-family: var(--font-sans, sans-serif);">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 330" role="img" aria-labelledby="spark-only-title spark-only-desc" style="display: block; flex: 1 1 280px; min-width: 0; width: 100%; max-width: 380px; height: auto; margin: auto;">
  <title id="spark-only-title">One machine</title>
  <desc id="spark-only-desc">One NVIDIA DGX Spark contains both a disposable review sandbox with the repository and harness, and DeepSeek Flash served by vLLM and SparkInfer. Model requests stay on the same machine and pass through a fixed relay.</desc>
  <defs><marker id="spark-only-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor"/></marker></defs>
  <text x="175" y="22" text-anchor="middle" font-size="18" font-weight="600" fill="currentColor">One machine</text>
  <rect x="8" y="40" width="334" height="280" rx="10" stroke-width="2" style="fill: var(--color-bg-card, #f3f4f6); stroke: var(--color-text-secondary, #64748b);"/>
  <text x="175" y="69" text-anchor="middle" font-size="18" font-weight="600" fill="currentColor">NVIDIA DGX Spark</text>
  <rect x="28" y="86" width="294" height="62" rx="6" stroke-dasharray="5 4" style="fill: var(--color-code-bg, #fff); stroke: var(--color-text-secondary, #64748b);"/>
  <text x="175" y="111" text-anchor="middle" font-size="17" fill="currentColor">Repository + harness</text>
  <text x="175" y="134" text-anchor="middle" font-size="14" style="fill: var(--color-text-secondary, #64748b);">Disposable sandbox</text>
  <path d="M 175 158 V 211" fill="none" stroke="currentColor" stroke-width="2" marker-end="url(#spark-only-arrow)"/>
  <text x="189" y="186" font-size="14" fill="currentColor">Fixed local relay</text>
  <rect x="28" y="225" width="294" height="70" rx="6" style="fill: var(--color-code-bg, #fff); stroke: var(--color-secondary, #0891b2);"/>
  <text x="175" y="253" text-anchor="middle" font-size="17" fill="currentColor">DeepSeek Flash</text>
  <text x="175" y="278" text-anchor="middle" font-size="15" style="fill: var(--color-text-secondary, #64748b);">vLLM + SparkInfer</text>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 330" role="img" aria-labelledby="split-machines-title split-machines-desc" style="display: block; flex: 1 1 280px; min-width: 0; width: 100%; max-width: 380px; height: auto; margin: auto;">
  <title id="split-machines-title">Two machines</title>
  <desc id="split-machines-desc">A separate review machine or VM contains the repository and harness in a disposable sandbox. Requests cross the private network through a fixed relay to an NVIDIA DGX Spark containing DeepSeek Flash served by vLLM and SparkInfer.</desc>
  <defs><marker id="split-machines-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor"/></marker></defs>
  <text x="175" y="22" text-anchor="middle" font-size="18" font-weight="600" fill="currentColor">Two machines</text>
  <rect x="8" y="40" width="334" height="110" rx="10" stroke-width="2" style="fill: var(--color-bg-card, #f3f4f6); stroke: var(--color-text-secondary, #64748b);"/>
  <text x="175" y="69" text-anchor="middle" font-size="18" font-weight="600" fill="currentColor">Review machine / VM</text>
  <rect x="28" y="86" width="294" height="43" rx="6" stroke-dasharray="5 4" style="fill: var(--color-code-bg, #fff); stroke: var(--color-text-secondary, #64748b);"/>
  <text x="175" y="113" text-anchor="middle" font-size="17" fill="currentColor">Repository + harness</text>
  <path d="M 175 160 V 214" fill="none" stroke="currentColor" stroke-width="2" marker-end="url(#split-machines-arrow)"/>
  <text x="189" y="181" font-size="14" fill="currentColor">Private network</text>
  <text x="189" y="202" font-size="14" fill="currentColor">via fixed relay</text>
  <rect x="8" y="228" width="334" height="92" rx="10" stroke-width="2" style="fill: var(--color-bg-card, #f3f4f6); stroke: var(--color-secondary, #0891b2);"/>
  <text x="175" y="254" text-anchor="middle" font-size="18" font-weight="600" fill="currentColor">NVIDIA DGX Spark</text>
  <text x="175" y="278" text-anchor="middle" font-size="17" fill="currentColor">DeepSeek Flash</text>
  <text x="175" y="301" text-anchor="middle" font-size="15" style="fill: var(--color-text-secondary, #64748b);">vLLM + SparkInfer</text>
</svg>
</div>
</figure>
<p>We used fresh review sandboxes with external connections blocked and a relay pointing only to our model. Our experiment was network isolated. For a physical air gap, transfer the model, images, rules and dependencies offline before starting.</p>
<h3 id="model-details">Model details</h3>
<p>We used <a href="https://huggingface.co/0xSero/deepseek-v4-flash-0731-spark" rel="noopener noreferrer" target="_blank">0xSero&rsquo;s adapted DeepSeek-V4-Flash-0731 checkpoint</a>, which occupies about 100 GiB. It removes 40 of the original 256 routed experts, the model&rsquo;s specialist subnetworks. REAP selects which experts to keep, and EXL3/Trellis compresses their weights to around 3 bits each. Our server allowed 262,144 tokens of context.</p>
<p>In our tests, generation speed varied from roughly 10 to 40 tokens per second. We have not compared this modified model&rsquo;s quality with the original release.</p>
<h2 id="the-tools-we-compared">The tools we compared</h2>
<p><a href="https://secmate.dev?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=local-airgapped-security-review&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_secmate" data-post-slug="local-airgapped-security-review" data-post-category="ai-security">SecMate</a> is optimized for smaller models and integrates with GitHub, GitHub Enterprise and GitLab.</p>
<p><a href="https://opencode.ai/docs/github/" rel="noopener noreferrer" target="_blank">OpenCode</a> is a general coding agent that also integrates with GitHub. For full scans, we added the community <a href="https://github.com/luanweslley77/opencode-security-analyze" rel="noopener noreferrer" target="_blank">security analysis plugin</a>, which guides it through discovery, investigation and review.</p>
<p><a href="https://github.com/arm/metis" rel="noopener noreferrer" target="_blank">Arm Metis</a> is a dedicated security review tool from Arm&rsquo;s Product Security Team. It supports patch and repository review with local model providers.</p>
<p>GitHub integration needs access to GitHub; our isolated benchmark reviewed local copies of the changes.</p>
<h2 id="the-benchmark">The benchmark</h2>
<p>We tested OpenCode 1.19.2, Metis 1.5.0 and SecMate at revision <code>038b74a</code>, all using the same model. We chose five documented vulnerabilities across JavaScript, Python and C.</p>
<div class="local-review-cases">
<table>
<thead>
<tr>
<th>Project</th>
<th>CVE</th>
<th>Target bug</th>
</tr>
</thead>
<tbody>
<tr>
<td>tar-fs</td>
<td><a href="https://github.com/google/security-research/security/advisories/GHSA-xrg4-qp5w-2c3w" rel="noopener noreferrer" target="_blank">CVE-2025-48387</a></td>
<td>Path validation regression allowing archive extraction outside the destination.</td>
</tr>
<tr>
<td>PyJWT</td>
<td><a href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-75c5-xw7c-p5pm" rel="noopener noreferrer" target="_blank">CVE-2024-53861</a></td>
<td>Partial issuer matches accepted instead of exact matches.</td>
</tr>
<tr>
<td>aiohttp</td>
<td><a href="https://github.com/aio-libs/aiohttp/security/advisories/GHSA-5h86-8mv2-jq9f" rel="noopener noreferrer" target="_blank">CVE-2024-23334</a></td>
<td>Files read outside the static directory with <code>follow_symlinks=True</code>.</td>
</tr>
<tr>
<td>path-to-regexp</td>
<td><a href="https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-9wv6-86v2-598j" rel="noopener noreferrer" target="_blank">CVE-2024-45296</a></td>
<td>Excessive regex backtracking that can block the server.</td>
</tr>
<tr>
<td>Expat</td>
<td><a href="https://github.com/libexpat/libexpat/issues/887" rel="noopener noreferrer" target="_blank">CVE-2024-45490</a></td>
<td>Negative lengths passed to <code>XML_ParseBuffer</code> can corrupt memory.</td>
</tr>
</tbody>
</table>
</div>
<p>Both modes targeted the same five bugs. PR reviews examined changes introducing or reintroducing each bug. Full scans searched vulnerable repository snapshots without a diff guiding them. We counted a bug as found when the report identified its behavior and an actionable code location.</p>
<h2 id="results">Results</h2>
<p>Times are averages across the five cases.</p>
<div class="local-review-results">
<h3 id="pr-reviews">PR reviews</h3>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Target bugs found</th>
<th>Average time</th>
</tr>
</thead>
<tbody>
<tr>
<td>OpenCode</td>
<td><span class="local-review-score" aria-hidden="true">●●●●○</span> 4 / 5</td>
<td>5m 44s</td>
</tr>
<tr>
<td>Metis</td>
<td><span class="local-review-score" aria-hidden="true">●●●●○</span> 4 / 5</td>
<td>6m 51s</td>
</tr>
<tr>
<td>SecMate</td>
<td><span class="local-review-score" aria-hidden="true">●●●●●</span> 5 / 5</td>
<td>8m 13s</td>
</tr>
</tbody>
</table>
<p>All three tools found at least four of the five target bugs when reviewing the changes that introduced or reintroduced them. In these cases, focused PR reviews finished in minutes, making them a manageable starting point for a local evaluation.</p>
<h3 id="full-repository-scans">Full repository scans</h3>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Target bugs found</th>
<th>Average time</th>
</tr>
</thead>
<tbody>
<tr>
<td>OpenCode + security plugin</td>
<td><span class="local-review-score" aria-hidden="true">●○○○○</span> 1 / 5</td>
<td>5m 26s</td>
</tr>
<tr>
<td>Metis</td>
<td><span class="local-review-score" aria-hidden="true">○○○○○</span> 0 / 5</td>
<td>3h 22m 19s</td>
</tr>
<tr>
<td>SecMate</td>
<td><span class="local-review-score" aria-hidden="true">●●●●○</span> 4 / 5</td>
<td>2h 49m 17s</td>
</tr>
</tbody>
</table>
<p>Without a diff to guide the review, every tool found fewer target bugs. Metis and SecMate took hours per case on average; OpenCode finished quickly but found only one target bug. A short runtime alone does not establish that a scan was useful. The review software affected both the findings and the time required, even though the model stayed the same.</p>
</div>
<p>These five known cases provide a starting comparison. We did not measure false-positive rates, analyst validation time or total operating cost.</p>
<h2 id="the-takeaway">The takeaway</h2>
<p>Teams whose code must stay on their own infrastructure can evaluate AI-assisted security review with a single-machine model server. In this comparison, focused PR reviews found more of the target bugs and took less time than the hours-long full scans. Start with a familiar PR containing a known bug, check whether the tool finds it, and review its evidence before expanding the scope.</p>
<p><a href="https://secmate.dev?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=local-airgapped-security-review&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_secmate" data-post-slug="local-airgapped-security-review" data-post-category="ai-security">SecMate</a> combines static analysis with AI investigation and validation to help security and engineering teams identify vulnerabilities and review the evidence behind each finding. The models and review setups behind all our <a href="https://secmate.dev/disclosures?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=local-airgapped-security-review&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_disclosures" data-post-slug="local-airgapped-security-review" data-post-category="ai-security">published vulnerability disclosures</a> can be deployed in an air-gapped environment. These discoveries include vulnerabilities in <a href="/posts/libcoap-vulnerabilities-disclosure/">libcoap</a>, <a href="/posts/rustfs-vulnerabilities-secmate-rust-support/">RustFS</a> and <a href="/posts/renesas-fsp-vulnerabilities/">Renesas FSP</a>.</p>
<aside class="local-review-cta">
<p>Discuss a local or air-gapped SecMate deployment on your infrastructure.</p>
<p><a href="https://secmate.dev/register?utm_source=blog&amp;utm_medium=body&amp;utm_campaign=local-airgapped-security-review&amp;utm_content=ai-security" rel="noopener noreferrer" target="_blank" data-cta-type="body_register" data-post-slug="local-airgapped-security-review" data-post-category="ai-security">Contact us</a></p>
</aside>
]]></content:encoded><media:content url="https://blog.secmate.dev/images/og_image.jpg" medium="image"/></item></channel></rss>