<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OBI EBUKA DAVID</title>
    <description>The latest articles on DEV Community by OBI EBUKA DAVID (@techstrtupninja).</description>
    <link>https://dev.to/techstrtupninja</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F630530%2F98c815f7-9800-47cd-b1d3-f8483636ff01.png</url>
      <title>DEV Community: OBI EBUKA DAVID</title>
      <link>https://dev.to/techstrtupninja</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/techstrtupninja"/>
    <language>en</language>
    <item>
      <title>We built an LLM that runs real pentests. The hard part was stopping it from lying</title>
      <dc:creator>OBI EBUKA DAVID</dc:creator>
      <pubDate>Wed, 08 Jul 2026 05:49:54 +0000</pubDate>
      <link>https://dev.to/techstrtupninja/we-built-an-llm-that-runs-real-pentests-the-hard-part-was-stopping-it-from-lying-57m5</link>
      <guid>https://dev.to/techstrtupninja/we-built-an-llm-that-runs-real-pentests-the-hard-part-was-stopping-it-from-lying-57m5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41litujlg2hsfli9ggvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41litujlg2hsfli9ggvm.png" alt=" " width="799" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We built an autonomous pentester on top of a large language model. It runs recon, picks and drives real offensive tools, exploits what it finds, and writes the report. The engineering that actually mattered was not teaching a model to hack. Models will happily "hack." The hard part was stopping it from telling us it found things that were not there.&lt;/p&gt;

&lt;p&gt;This is the build story of Nemesis Red, and specifically the problem everyone building LLM security tooling smashes into: hallucinated findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why most LLM pentest demos are demoware
&lt;/h2&gt;

&lt;p&gt;Point a model at a target, ask it to find vulnerabilities, and it will hand you a confident, well-formatted list. Some of it is real. Some of it is invented. From the text alone you cannot tell which, and in security a false positive is not a rounding error. It burns an analyst's afternoon, it erodes trust in the tool, and at scale it makes the output worthless.&lt;/p&gt;

&lt;p&gt;A model that says "the login form is vulnerable to SQL injection" has told you nothing you can act on. A model that says "here is the injection, here is the exact request I sent, here is the database version it returned" has told you everything. The gap between those two sentences is the entire product.&lt;/p&gt;

&lt;h2&gt;
  
  
  ReasonChain: prove it or it did not happen
&lt;/h2&gt;

&lt;p&gt;The core of Nemesis Red is an engine we call ReasonChain. The rule it enforces is easy to state and annoying to build: the model is never trusted on its own word. Every claim it makes gets executed against the real target and checked against ground truth before it counts as a finding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8456y142zvvrhlzryun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8456y142zvvrhlzryun.png" alt=" " width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The model forms a hypothesis. "This parameter looks injectable."&lt;/li&gt;
&lt;li&gt;It selects and runs a real tool to test that hypothesis, against the actual target, not a simulation.&lt;/li&gt;
&lt;li&gt;The result is checked against an objective signal. Did the payload return the data. Did the shell open. Did the scoreboard flip.&lt;/li&gt;
&lt;li&gt;Only a hypothesis that survives step 3 becomes a finding. Everything else is discarded, including the things the model was completely sure about.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is closer to how a human pentester works than to how a chatbot works. You do not write "SQLi confirmed" in a report because the app looked suspicious. You write it because you pulled a row out of the database. ReasonChain holds the model to that same standard.&lt;/p&gt;

&lt;p&gt;The effect on output quality is the whole point. The model is allowed to be wrong in private as many times as it likes. It is not allowed to be wrong in the report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Driving 290 tools instead of reimplementing them
&lt;/h2&gt;

&lt;p&gt;We did not try to teach the model to exploit things from scratch. The offensive tooling already exists and is battle-tested. Nemesis Red orchestrates around 290 tools from the Kali ecosystem across 17 categories, and the model's job is to be the operator: pick the right tool for the current phase and target type, run it, read the output, and decide the next move.&lt;/p&gt;

&lt;p&gt;That framing matters. The model is not a hacker in a vacuum, it is a decision layer on top of tools that already work. Recon feeds exploitation feeds reporting in a closed loop, with the model choosing the path and the tools doing the actual work. When the model picks wrong, the verification step catches it, because a tool that finds nothing produces no ground-truth signal to promote into a finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  We measured it, and kept the methodology attached
&lt;/h2&gt;

&lt;p&gt;Claims about "AI finds more" are cheap, so here is ours with the method attached.&lt;/p&gt;

&lt;p&gt;In a controlled ablation, Nemesis Red produced &lt;strong&gt;24.4 times more valid findings&lt;/strong&gt; than fixed-script automation on the same targets. The setup: 30 OWASP-class targets, 120 runs, across four conditions. The full system, then three ablations that each remove one capability: no replanning, no fusion of results across steps, and randomized tool order instead of reasoned order. Wilcoxon signed-rank, W = 465, p &amp;lt; 0.001.&lt;/p&gt;

&lt;p&gt;The ablations are the interesting part, because they say where the lift comes from. Removing replanning hurts. Removing cross-step fusion hurts. Randomizing the order the model would otherwise reason its way to hurts. The gain is not "we called an LLM," it is the reasoning loop wrapped around the tools. Strip the reasoning and you are back to scripted scanning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receipts
&lt;/h2&gt;

&lt;p&gt;On known-vulnerable targets during the study, Nemesis Red autonomously identified and exploited three critical vulnerabilities rated CVSS 9.8, and confirmed each with a working exploit rather than a scanner flag:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CVE-2024-38476 (Apache mod_rewrite SSRF)&lt;/li&gt;
&lt;li&gt;CVE-2024-38474 (Apache mod_rewrite substitution)&lt;/li&gt;
&lt;li&gt;CVE-2023-25690 (HTTP request smuggling)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be precise about what that is and is not: these are known, published N-day CVEs, not novel zero-days. The result is that the system chained a full exploit against each on its own and proved it, with no human steering the steps. Novel zero-day discovery is a different and harder problem, and we treat it as a separate thing rather than blurring the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local by default, because pentest data is sensitive
&lt;/h2&gt;

&lt;p&gt;A detail that matters for anyone who would actually run this: you should not have to ship a client's live vulnerabilities to a third-party API to use the tool. Nemesis Red is bring-your-own-key for the frontier models (Anthropic, OpenAI, Gemini) if you want their reasoning, but it also runs fully local against an Ollama model (Qwen, Llama, or your own fine-tune). Local is slower and a little less sharp, but for engagements where the target data cannot leave the environment, "a little less sharp and it never leaves the box" is the correct trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways to run it
&lt;/h2&gt;

&lt;p&gt;The same engine runs at three levels of autonomy, depending on how much you want to hand over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Copilot.&lt;/strong&gt; A human drives, the model reads tool output and pre-fills the next moves. For testers who want speed without giving up the wheel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous vulnerability assessment.&lt;/strong&gt; The model runs the discovery and verification loop and hands you a verified findings list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous penetration test.&lt;/strong&gt; Recon to exploit to report, hands off.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it gets wrong, honestly
&lt;/h2&gt;

&lt;p&gt;Before verification, the model is exactly as overconfident as every other LLM. The entire architecture exists because raw model output is not trustworthy, and if you deleted the verification layer you would have the same demoware problem as everyone else. Verification also costs time and tool executions, so a run is not free. And autonomy needs guardrails: a system driving offensive tools on its own has to be scoped hard to the authorized target set, which is a first-class design concern, not an afterthought.&lt;/p&gt;

&lt;p&gt;None of that is a reason not to build it. It is the reason to build it with proof in the loop instead of vibes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits
&lt;/h2&gt;

&lt;p&gt;Nemesis Red is the offensive half of what we are building. The defensive half, Nemesis Blue, is a Rust EDR with a completely different build story that I wrote up separately.&lt;/p&gt;

&lt;p&gt;If you want to see it run or get your hands on it, we are at &lt;a href="//nemesislabs.xyz"&gt;nemesislabs.xyz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>We built a Rust EDR. macOS notarization tried to kill it.</title>
      <dc:creator>OBI EBUKA DAVID</dc:creator>
      <pubDate>Wed, 08 Jul 2026 02:19:08 +0000</pubDate>
      <link>https://dev.to/techstrtupninja/we-built-a-rust-edr-macos-notarization-tried-to-kill-it-363f</link>
      <guid>https://dev.to/techstrtupninja/we-built-a-rust-edr-macos-notarization-tried-to-kill-it-363f</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp6ctd604zlu5g16fip7e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp6ctd604zlu5g16fip7e.png" alt=" " width="800" height="514"&gt;&lt;/a&gt;&lt;br&gt;
Over the last few months we shipped Nemesis Blue, an endpoint detection and response agent written in Rust, notarized and running on macOS. This is the build story: why Rust, what notarization actually costs you, the entitlement bug that ate a week, and how you do detection engineering inside Apple's hardened runtime.&lt;/p&gt;

&lt;p&gt;No marketing here. Just the parts that were hard.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Rust for an EDR
&lt;/h2&gt;

&lt;p&gt;An EDR runs on every machine you protect, with high privilege, all the time. That job description rules a lot of things out. A garbage-collected runtime that pauses mid-scan is not acceptable. A memory-safety bug in an agent that sits just above the kernel is an incident waiting to happen, on your customer's box, with your signature on it.&lt;/p&gt;

&lt;p&gt;Rust gave us three things that mattered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No GC pauses. Scans run in bounded time, every time.&lt;/li&gt;
&lt;li&gt;Memory safety without a runtime. The agent ships as a single static binary.&lt;/li&gt;
&lt;li&gt;One codebase across platforms. Our crates (&lt;code&gt;nemesis-core&lt;/code&gt;, &lt;code&gt;nemesis-scan&lt;/code&gt;, &lt;code&gt;nemesis-detect&lt;/code&gt;, and friends) build for macOS, Linux, and Windows sensors out of the same Cargo workspace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last decision paid off later: once the macOS agent was solid, the Linux build came up end to end in days instead of weeks, because everything below the platform layer was already shared and tested.&lt;/p&gt;
&lt;h2&gt;
  
  
  Notarization is the part nobody warns you about
&lt;/h2&gt;

&lt;p&gt;If you want a macOS binary to run on someone else's machine without a scary Gatekeeper wall, you notarize it. To notarize, Apple requires the &lt;strong&gt;hardened runtime&lt;/strong&gt;. And the hardened runtime quietly changes the rules your process runs under: no unsigned executable memory, no loading unsigned libraries, restricted debugging, and by default, no JIT.&lt;/p&gt;

&lt;p&gt;That "no JIT" line is where we lost a week.&lt;/p&gt;
&lt;h2&gt;
  
  
  The SIGKILL that ate a week
&lt;/h2&gt;

&lt;p&gt;Our scanning engine is built on &lt;strong&gt;YARA-X&lt;/strong&gt;, the Rust rewrite of YARA. YARA-X compiles rules down and runs them on &lt;strong&gt;wasmtime&lt;/strong&gt;. Wasmtime is a JIT: to execute, it allocates memory, marks it executable, and jumps into it.&lt;/p&gt;

&lt;p&gt;Under a normal build, this is invisible. Under the hardened runtime, the kernel refuses to hand you executable-writable pages. The moment the scanner tried to run its first rule, the whole daemon died. Not an exception we could catch. An immediate &lt;code&gt;SIGKILL&lt;/code&gt;, with Console showing a code-signature violation.&lt;/p&gt;

&lt;p&gt;The symptom was maddening because everything worked in development and died the instant it was signed and hardened. Same binary, different fate, depending on entitlements.&lt;/p&gt;

&lt;p&gt;The fix is one entitlement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;com.apple.security.cs.allow-jit&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it, re-sign, re-notarize, and wasmtime can allocate its JIT pages again. Obvious in hindsight. Not obvious at 2am when your only clue is a process that vanishes without a stack trace.&lt;/p&gt;

&lt;p&gt;The lesson we took from it: on macOS, your entitlements are part of your runtime behavior, not a checkbox at the end. If a dependency touches executable memory, dynamic libraries, or the network, that shows up here or your process dies in ways your test suite never sees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection engineering under the hardened runtime
&lt;/h2&gt;

&lt;p&gt;With the engine actually running, the real work is detection. Nemesis Blue runs three layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signatures.&lt;/strong&gt; YARA-X rules for known families and behaviors. Fast, explainable, and the thing an analyst can read and trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Machine learning.&lt;/strong&gt; An XGBoost model trained on the EMBER feature set for static classification of executables. The model is the interesting supply-chain problem: if an attacker can swap your model file, they own your verdicts. So model bundles are signed with &lt;strong&gt;Ed25519&lt;/strong&gt;, and the agent verifies the signature before it will load a model. A model that does not verify does not run. Retraining happens weekly in CI, and it only publishes when the labeled corpus is large enough to be worth shipping. New models roll out to a canary slice of the fleet first, so a bad training run degrades a handful of machines instead of all of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IOC matching and quarantine.&lt;/strong&gt; Indicator feeds for the known-bad, and quarantine to pull a file out of harm's way once something fires.&lt;/p&gt;

&lt;p&gt;None of these are novel on their own. The engineering is in making all three run in bounded time, on someone else's laptop, without being the reason their fan spins up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 78-second freeze
&lt;/h2&gt;

&lt;p&gt;Memory scanning is where we hit the ugliest performance bug. Our first pass at walking a process's memory regions shelled out and parsed the output. On small processes it was fine. On a large one, it serialized behind a single call that blocked for &lt;strong&gt;78 seconds&lt;/strong&gt;. For an agent that is supposed to be invisible, 78 seconds of a pegged process is not a bug, it is an eviction notice.&lt;/p&gt;

&lt;p&gt;The fix was to stop treating memory enumeration as a subprocess and read the regions directly, with hard caps on region size and early skips for the mappings we never scan. Bounded work, off the hot path. The 78 seconds became milliseconds.&lt;/p&gt;

&lt;p&gt;This is the recurring theme of EDR work: correctness is table stakes, but the thing that gets you uninstalled is being heavy. Every scan has to answer "what did this cost the user."&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping, and staying shipped
&lt;/h2&gt;

&lt;p&gt;The agent ships as a notarized &lt;code&gt;.pkg&lt;/code&gt;. But shipping once is not the hard part. Keeping a fleet current is.&lt;/p&gt;

&lt;p&gt;Nemesis Blue agents check for updates at boot and every few hours after, on a stable channel, and self-install a newer signed and notarized package when one is published. Pushing a release is: bump the version, build the package, notarize it, publish the manifest. Because updates are gated behind signing and notarization, a compromised update server still cannot push a payload the agents will accept. The agents only run what Apple and our signing key both vouch for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it honestly does today
&lt;/h2&gt;

&lt;p&gt;Here is the part most product posts skip. As of today, Nemesis Blue does detection: scanning, YARA-X, the ML classifier, IOC matching, quarantine, and monitoring, all in a notarized agent you can install right now.&lt;/p&gt;

&lt;p&gt;What it does not do yet is real-time blocking. Full inline enforcement (killing a malicious process before it executes, streaming kernel events, process attribution) depends on Apple's &lt;strong&gt;Endpoint Security&lt;/strong&gt; entitlement, which is a manual review with a multi-week queue. We have it submitted. Until it clears, enforce mode stays behind the flag, and we would rather say that plainly than imply a capability we cannot ship. The moment the entitlement lands, the blocking path is already built and waiting for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;If you are building a signed, notarized native agent on macOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat entitlements as runtime behavior. &lt;code&gt;allow-jit&lt;/code&gt; for anything wasm or JIT, and audit every dependency for what the hardened runtime will forbid.&lt;/li&gt;
&lt;li&gt;Sign your models, not just your binary. A swapped model is a swapped verdict.&lt;/li&gt;
&lt;li&gt;Measure what every scan costs the user. Heavy gets you uninstalled faster than wrong.&lt;/li&gt;
&lt;li&gt;Be honest about what is gated. The entitlement queue is real, and pretending otherwise just burns trust with the exact people who will read your Console logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nemesis Blue is the defensive half of what we are building at Nemesis Labs. The offensive half, Nemesis Red, is an autonomous pentest engine, and it has its own build story that is nothing like this one. That post is next.&lt;/p&gt;

&lt;p&gt;If you want to follow along or kick the tires, we are at nemesislabs.xyz.&lt;/p&gt;

</description>
      <category>security</category>
      <category>rust</category>
      <category>devops</category>
      <category>macos</category>
    </item>
  </channel>
</rss>
