<?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: Jeriah Keith</title>
    <description>The latest articles on DEV Community by Jeriah Keith (@yeriahz).</description>
    <link>https://dev.to/yeriahz</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%2F4052222%2F155352d5-808b-48a4-9ef4-3bd9a675b6f6.jpg</url>
      <title>DEV Community: Jeriah Keith</title>
      <link>https://dev.to/yeriahz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yeriahz"/>
    <language>en</language>
    <item>
      <title>119 Tests Passed. The One Named After the Bug Passed Too.</title>
      <dc:creator>Jeriah Keith</dc:creator>
      <pubDate>Sun, 16 Aug 2026 09:28:03 +0000</pubDate>
      <link>https://dev.to/yeriahz/119-tests-passed-the-one-named-after-the-bug-passed-too-1iim</link>
      <guid>https://dev.to/yeriahz/119-tests-passed-the-one-named-after-the-bug-passed-too-1iim</guid>
      <description>&lt;p&gt;My test suite came back green. 119 passed, 3 skipped, under a second.&lt;/p&gt;

&lt;p&gt;At that exact moment, my tool was telling people to do the one thing a test in that suite promised it never told anyone to do. The test was named after the promise. It ran. It passed.&lt;/p&gt;

&lt;p&gt;That gap between what a test is named and what it actually checks is the most expensive thing I have found in this project. I do not think it is rare, and the shape of it transfers to almost any codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second version of what the tool does
&lt;/h2&gt;

&lt;p&gt;I built a scanner that checks a company's email authentication setup from public DNS records, then generates a plain-English page telling them what to publish to fix it. Small accounting firms, mostly. They take that page to whoever runs their DNS and paste in the records.&lt;/p&gt;

&lt;p&gt;That last part is the whole risk. The output is not a report someone reads and nods at. It is a set of instructions someone follows. If the instruction is wrong, a real business loses real mail.&lt;/p&gt;

&lt;p&gt;The relevant feature is a staged rollout, a ladder. Each rung is one DNS record to publish, in order, with a stage label attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  The advice it got wrong
&lt;/h2&gt;

&lt;p&gt;One DMARC setting matters here: a tag called &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A domain can publish "reject anything that fails authentication" and simultaneously publish &lt;code&gt;t=y&lt;/code&gt;, which means "but don't actually do that yet, I'm still testing." Think of &lt;code&gt;t=y&lt;/code&gt; as a parking brake. The policy is set. The brake is on.&lt;/p&gt;

&lt;p&gt;Removing that brake is safe once your mail is properly signed. Removing it before that is how a company starts bouncing its own invoices.&lt;/p&gt;

&lt;p&gt;So the tool has a rule. If a domain has the brake on and no working mail signing, do not tell them to take the brake off. Tell them to leave it alone and go fix signing first. That rung exists, it works, and it is the first thing on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Not yet - keep the t=y tag until DKIM is signing&lt;/span&gt;
&lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v=DMARC1; p=quarantine; t=y; rua=mailto:r@example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Correct. Brake intact.&lt;/p&gt;

&lt;p&gt;Here is the second rung on that same page, for that same unsigned domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Next - after 2 weeks of clean reports, and only once DKIM is signing&lt;/span&gt;
&lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc@x.test; fo=1;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;t&lt;/code&gt; tag anywhere in it. Step one says keep the brake on. Step two hands over a record with the brake gone and the policy escalated, on the same page, to the same client.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test that was written to prevent this
&lt;/h2&gt;

&lt;p&gt;This is the part that should bother you, because it is the part I would have sworn was covered:&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;test_no_rung_offered_to_an_unsigned_domain_removes_its_test_mode_brake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Weights&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;assess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dkim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dmarc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;policy_test_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not in test mode; no brake to remove&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;brake_removed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;strip_test_mode_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rung&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;dmarc_rollout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x.test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;rung&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;brake_removed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the name. Then read the assertion.&lt;/p&gt;

&lt;p&gt;The name claims: &lt;strong&gt;no rung removes the brake.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The assertion checks: &lt;strong&gt;no rung equals this one specific string.&lt;/strong&gt; That string is the input record with the tag deleted and every other byte left identical.&lt;/p&gt;

&lt;p&gt;Those are not the same claim, and the distance between them is exactly where four bad outputs were living. The offending rung was &lt;code&gt;v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc@x.test; fo=1;&lt;/code&gt;. It has no brake. It is also not the input-minus-the-tag, because the policy changed and the other tags were regenerated. Different string. &lt;code&gt;!=&lt;/code&gt; holds. Test passes. Bug ships.&lt;/p&gt;

&lt;p&gt;The test was not missing. It was not skipped. It ran on exactly the right input, in exactly the right scenario, and reported success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three more guards, all blind, all reasonable
&lt;/h2&gt;

&lt;p&gt;This is the part I want any engineer reading to sit with. It was not one weak test. It was four, and each one was defensible on its own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 1. The string comparison above.&lt;/strong&gt; It checked one exact value out of an unbounded set of wrong values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 2. "No suggested record drops the tag."&lt;/strong&gt; Same technique, same blind spot. Two tests, one assumption, zero independence. Two guards that share an assumption are one guard wearing a disguise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 3. Publish the advice, then re-scan.&lt;/strong&gt; Good design, this one: take the record the page tells you to publish, publish it in a simulated zone, run the whole assessment again, confirm the domain is still braked. It passed because it read only the &lt;strong&gt;first&lt;/strong&gt; rung. The first rung was the correct one. It never looked at rung two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 4. "Following any step must not introduce a critical finding."&lt;/strong&gt; The finding it watches for is triggered by the policy value alone. On a domain already set to &lt;code&gt;quarantine&lt;/code&gt;, that finding had &lt;em&gt;already fired&lt;/em&gt;. You cannot introduce something that is already present. The guard was structurally incapable of failing on this input.&lt;/p&gt;

&lt;p&gt;Four layers. One live path straight through all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I actually found it
&lt;/h2&gt;

&lt;p&gt;Not by reading the code. I had read that function. I had an opinion about it. My opinion identified &lt;strong&gt;one&lt;/strong&gt; faulty code path.&lt;/p&gt;

&lt;p&gt;What I did instead was enumerate. I wrote a throwaway script that took every relevant input state, ran it through the ladder, and printed every single rung it produced into a table. One column ran each generated record back through the real parser and asked, plainly, "does this still have the brake on?"&lt;/p&gt;

&lt;p&gt;Eighteen rungs. Four with the brake removed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;input&lt;/th&gt;
&lt;th&gt;stage&lt;/th&gt;
&lt;th&gt;brake in output?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p=quarantine; t=y; rua=…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Next - ...only once DKIM is signing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;gone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p=quarantine; t=y; adkim=s; ruf=…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Next - ...only once DKIM is signing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;gone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p=reject; t=y&lt;/code&gt; (no reporting)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Repair&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;gone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p=reject; t=y; pct=20; rua=…&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Repair&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;gone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three separate code paths, not one. My reasoning had found a third of the problem and felt finished.&lt;/p&gt;

&lt;p&gt;Now look at the bottom two rows. Those are labeled &lt;code&gt;Repair&lt;/code&gt;. Not "only once DKIM is signing." Just &lt;code&gt;Repair&lt;/code&gt;. Flat, unqualified, no warning attached anywhere. The safety caveat had been added to the escalation steps and never to the repair steps, because when that caveat was written nobody was thinking about repairs. A client reads a step called "Repair," assumes repairs are safe, and pastes it in.&lt;/p&gt;

&lt;p&gt;The root cause was mundane, by the way. A branch appended its rung and did not &lt;code&gt;return&lt;/code&gt;. Execution fell straight through into the three branches below it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I take from this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A test's name is documentation, and documentation drifts.&lt;/strong&gt; The name was written when the intent was fresh. The assertion was written to the example in front of me that day. Nobody reconciled them afterward, because the test was green and green means done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assert on the property, not on a value.&lt;/strong&gt; &lt;code&gt;!= "one_known_bad_string"&lt;/code&gt; is not a guarantee. Parsing the output and asking "does this have the property I care about?" is. Same test, ten more lines, and it would have caught all four.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Count your independent guards, not your total guards.&lt;/strong&gt; I had four. Two shared a technique, one read only the first element, and one was watching a condition that was already true. That is not four layers of defense. That is one, and it was the weak one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enumerate the output space.&lt;/strong&gt; Every real error in this project, mine and the AI assistant's I use on it, came from reasoning about what code would do instead of running it and printing what it did. Reasoning gave me one code path. A table gave me three. The table took fifteen minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutation-test in both directions.&lt;/strong&gt; A guard that should fire must be shown to fire. A guard that should stay quiet must be shown to stay quiet. An assertion no one has ever seen fail is a hypothesis, not a test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;I caught this in a working tree, mid-change, before the feature was finished. Not from a client call. That is the good outcome, and I only got it because I stopped trusting a green checkmark long enough to enumerate what the thing actually emits.&lt;/p&gt;

&lt;p&gt;The fix is not obvious, which is why it is still open. Carrying the brake tag forward onto an escalation step means handing someone a record that says "reject everything, but not yet," which is confusing on its own terms. Suppressing those rungs entirely means the page goes quiet about a real next step. Both are defensible. That is a product decision, not a test decision, and I would rather sit with it a day than patch it because a table embarrassed me.&lt;/p&gt;

&lt;p&gt;The test is getting rewritten either way. Right now its name is a promise its assertion does not keep, and that is worse than having no test at all. A missing test is an obvious gap. A lying test is a gap you have already convinced yourself is covered.&lt;/p&gt;

&lt;p&gt;Go look at your suite. Find a test whose name makes a broad claim. Read what it actually asserts.&lt;/p&gt;

&lt;p&gt;I would bet you find at least one.&lt;/p&gt;




&lt;h2&gt;
  
  
  For the curious
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The sweep.&lt;/strong&gt; The whole thing was about forty lines. Every input state, through the ladder, one row per rung, and one column that did the actual work:&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;parses_as_test_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run a candidate record back through the real parser.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dmarc_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FakeResolver&lt;/span&gt;&lt;span class="p"&gt;({(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_dmarc.probe.test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;probe.test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;policy_test_mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the difference between the guard that missed and the one that would have caught it. The failing guard asked "is this string equal to that string." This asks "does the thing I am about to hand a client still have the property I promised." Same effort. Different question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the parking brake is only half a brake.&lt;/strong&gt; &lt;a href="https://datatracker.ietf.org/doc/html/rfc9989" rel="noopener noreferrer"&gt;RFC 9989&lt;/a&gt; is the current DMARC standard, and it defines &lt;code&gt;t&lt;/code&gt; in section 4.7 with a default of &lt;code&gt;n&lt;/code&gt;. It obsoletes &lt;a href="https://datatracker.ietf.org/doc/html/rfc7489" rel="noopener noreferrer"&gt;RFC 7489&lt;/a&gt;. That transition is the part worth knowing: a receiver still running the older spec does not recognise &lt;code&gt;t&lt;/code&gt; at all. It ignores the tag and applies the published policy anyway. So the brake works on some receivers and not others, which is why the tool never tells anyone the tag is protecting their mail. It only ever says the tag is why some receivers are holding off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the test names look like now.&lt;/strong&gt; The suite reads as sentences, which is how I noticed the problem at all. &lt;code&gt;test_no_rung_offered_to_an_unsigned_domain_removes_its_test_mode_brake&lt;/code&gt; is a claim you can check against its own body. A test called &lt;code&gt;test_rollout_3&lt;/code&gt; is not. Naming tests as assertions is worth doing on its own merits, and it comes with a cost nobody mentions: a name that specific will eventually promise more than the assertion delivers, and you will believe the name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The code.&lt;/strong&gt; The scanner is at &lt;a href="https://github.com/Yeriahz/Mailauth" rel="noopener noreferrer"&gt;Mailauth&lt;/a&gt;, bug and all. Passive DNS only, no probing, MIT licensed.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>python</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Program Said the Cage Was Locked. I Asked the Kernel.</title>
      <dc:creator>Jeriah Keith</dc:creator>
      <pubDate>Wed, 05 Aug 2026 01:50:58 +0000</pubDate>
      <link>https://dev.to/yeriahz/the-program-said-the-cage-was-locked-i-asked-the-kernel-42a0</link>
      <guid>https://dev.to/yeriahz/the-program-said-the-cage-was-locked-i-asked-the-kernel-42a0</guid>
      <description>&lt;p&gt;The framework told me the sandbox was applied. I wanted a second opinion, so I asked the kernel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep &lt;/span&gt;Seccomp /proc/10920/status /proc/10922/status
/proc/10920/status:Seccomp:     0
/proc/10920/status:Seccomp_filters:     0
/proc/10922/status:Seccomp:     2
/proc/10922/status:Seccomp_filters:     1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;10920 is the agent. 10922 is the worker it forked to run model-written code. The worker has a seccomp filter loaded and the parent does not. That is the network block, applied to exactly the process that should have it and to nothing else.&lt;/p&gt;

&lt;p&gt;That took ten seconds and it is the first thing in this whole project that I verified against something other than the program's own report.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was doing
&lt;/h2&gt;

&lt;p&gt;I run AI agent frameworks that execute code a language model writes. NVIDIA's &lt;a href="https://arxiv.org/abs/2607.20709" rel="noopener noreferrer"&gt;NOOA&lt;/a&gt; is the one I have been studying. Its own documentation is unusually blunt: the static checks and deny-lists are guardrails, not a containment boundary, and the real boundary is OS-level isolation.&lt;/p&gt;

&lt;p&gt;It ships one. Each block of generated code runs in a forked worker with Landlock confining the filesystem, seccomp blocking network sockets, resource caps, and a hard timeout. Appendix D.2 of their paper describes the deployment of it, including a known gap in their own in-process guard published alongside the backstop that catches it.&lt;/p&gt;

&lt;p&gt;So the question was not whether the design is sound. It is. The question was whether the thing described in the paper was actually running on my machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first surprise
&lt;/h2&gt;

&lt;p&gt;It was not.&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="n"&gt;execution_backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inprocess&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inprocess&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The OS sandbox is opt-in. Every agent run I had done executed model-written Python in the agent's own process, protected by the AST validator and deny-lists that the documentation explicitly tells you are not a containment boundary.&lt;/p&gt;

&lt;p&gt;Nothing was wrong. The VM I had built was doing the work, which is exactly what the README says to do. But I had assumed a layer was there because I had read its source, and reading source is not the same as checking what ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the kernel will and will not tell you
&lt;/h2&gt;

&lt;p&gt;Turned on, the guards became checkable. Not all of them the same way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seccomp&lt;/strong&gt; is readable per process. That is the differential above, and it is the strongest kind of evidence available: the kernel reporting on a process, not the process reporting on itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource caps&lt;/strong&gt; read as unlimited on both processes. That looked like a finding until I read the config: &lt;code&gt;max_memory_mb&lt;/code&gt; and &lt;code&gt;max_cpu_seconds&lt;/code&gt; both default to &lt;code&gt;0&lt;/code&gt;, which means disabled. Nothing was requested, so nothing was applied. The config and the kernel agreed. I had just not read the config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Landlock&lt;/strong&gt; cannot be read back at all. Once a process applies a ruleset the restriction is real and irrevocable, but there is no &lt;code&gt;/proc&lt;/code&gt; field for it. The differential trick does not work. The only way to confirm it is behavioural: have the confined process try to read something outside its allowed paths and watch it fail.&lt;/p&gt;

&lt;p&gt;That is worth sitting with. Of three guards, one is directly observable, one is off by design, and one can only be demonstrated. If you want to know your sandbox holds, "I configured it" is not an answer for any of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Their tests already do this
&lt;/h2&gt;

&lt;p&gt;I was about to write a Landlock probe when I found NVIDIA had written one. Forty-six of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;uv run pytest tests/runtime/sandbox/ &lt;span class="nt"&gt;-m&lt;/span&gt; integration &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="go"&gt;46 passed, 23 deselected in 22.48s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Twenty-two seconds, because they use a fake LLM client. No model, no inference, no credentials. Containment becomes testable in the time it takes to read the output.&lt;/p&gt;

&lt;p&gt;And they are built the way you would want. &lt;code&gt;test_guards.py&lt;/code&gt; has &lt;code&gt;test_file_read_leak_without_sandbox&lt;/code&gt; and &lt;code&gt;test_file_read_closed_with_sandbox&lt;/code&gt;. Leak first, then closed. Same for memory, same for network. They do not accept a passing check without first showing the same thing fails when the guard is off.&lt;/p&gt;

&lt;p&gt;That is the discipline I had written a whole post about, sitting in the suite of the project I was studying, applied to every guardrail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I checked whether they run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uv run pytest -q -m "not integration and not stress"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is line 38 of &lt;code&gt;ci.yml&lt;/code&gt;, and it is the only pytest invocation in the entire workflow directory. All forty-six containment tests carry the &lt;code&gt;integration&lt;/code&gt; marker. None of them execute in CI.&lt;/p&gt;

&lt;p&gt;The exclusion is not careless. Twelve test files carry that marker and six of them are live-provider tests that genuinely need API credentials, which cannot run in CI at all. The marker means "needs credentials" for that group and "forks a real worker" for the sandbox group, and one filter catches both.&lt;/p&gt;

&lt;p&gt;I checked the obvious defence: maybe the sandbox tests would fail on a runner without Landlock or seccomp. They would not. Every &lt;code&gt;SandboxConfig&lt;/code&gt; in the file passes &lt;code&gt;require=False&lt;/code&gt;, and the four tests that need a specific mechanism carry skip conditions. On a kernel without those features they skip rather than fail.&lt;/p&gt;

&lt;p&gt;So: a working containment suite, correctly written, with paired negative controls, that has never run automatically. Not a broken guard. A guard nobody is watching.&lt;/p&gt;

&lt;p&gt;I filed it as &lt;a href="https://github.com/NVIDIA-NeMo/labs-OO-Agents/issues/78" rel="noopener noreferrer"&gt;issue #78&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part where I stop sounding clever
&lt;/h2&gt;

&lt;p&gt;While all this was going on, my own verification script broke twice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/yeriahz/the-security-check-that-couldnt-fail-2d4h"&gt;Six days ago I wrote&lt;/a&gt; about the first version, which printed a green OK it was structurally incapable of not printing. I fixed that and added a check that compares the full set of configuration keys the platform reports against a known-good baseline, so a renamed key fails mechanically instead of requiring me to notice that the output looked short.&lt;/p&gt;

&lt;p&gt;Then it failed for a reason that had nothing to do with drift.&lt;/p&gt;

&lt;p&gt;I had captured the baseline while the VM was running. A running VM reports keys that a powered-off one does not, so comparing across states flagged ten of them as renames. Ten failures, none real.&lt;/p&gt;

&lt;p&gt;I fixed that by recording the state in the baseline, re-captured, and it failed again. Four more keys, all guest-reported, which appear about a minute after boot once the guest registers its facilities. I had captured thirty seconds in.&lt;/p&gt;

&lt;p&gt;Three versions, three failures, all the same class: the check's relationship to reality untested across the conditions it actually runs in. Could not fail. Fired falsely across states. Fired falsely within a state depending on timing.&lt;/p&gt;

&lt;p&gt;The thing that caught the second one is the part I would not have predicted. An hour earlier I had written a regeneration script whose entire design was to make silencing a failure expensive: no force flag, no non-interactive mode, and any key you drop has to be typed back by hand. I built it so I could not quietly delete a real failure. Its first act was to stop me quietly deleting a fake one.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more, from a different direction
&lt;/h2&gt;

&lt;p&gt;The same week, a missing API key cost me an afternoon.&lt;/p&gt;

&lt;p&gt;The error said &lt;code&gt;InternalServerError&lt;/code&gt;. Five hundred. So it got retried, three times, and the useful sentence arrived at the bottom of a two-hundred-line traceback.&lt;/p&gt;

&lt;p&gt;The chain: the OpenAI SDK raises at client construction, before any HTTP request, so its exception carries no status code. litellm's handler defaults a missing status to 500. The mapper sees 500 and calls it a server error.&lt;/p&gt;

&lt;p&gt;But a missing status code means no HTTP exchange happened. Defaulting it to 500 asserts that a server responded with a server error. Nothing responded. Nothing was asked.&lt;/p&gt;

&lt;p&gt;Same shape as everything else here: a layer reporting confidently about something it was not in a position to know. Filed as &lt;a href="https://github.com/BerriAI/litellm/issues/35860" rel="noopener noreferrer"&gt;litellm #35860&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually took from it
&lt;/h2&gt;

&lt;p&gt;Every layer in this stack reports on itself, and every one of those reports is worth exactly as much as the layer's ability to be wrong about it.&lt;/p&gt;

&lt;p&gt;The framework says the sandbox is applied. It is reporting that it asked. The test suite says green. It is reporting on the tests that ran, not the ones that were filtered out. My script says the configuration matches. It is reporting on the keys it thought to look for, in whatever state it happened to be told about.&lt;/p&gt;

&lt;p&gt;None of those are lies. They are all narrower claims than they sound.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The useful question is not "does it say it's fine". It's "what would have to be true for it to say that, and is any of it checked by something other than itself".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes there is an answer sitting right there. The kernel knows which process has a seccomp filter. &lt;a href="https://dev.to/yeriahz/it-printed-verifying-it-verified-nothing-1cde"&gt;A content-addressed store's filenames are the checksums&lt;/a&gt;. A test suite knows which tests it skipped. None of that requires trusting the thing you are checking.&lt;/p&gt;

&lt;p&gt;And sometimes there isn't one, like Landlock, and then the only honest move is to break the thing on purpose and watch what happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  For the curious
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The two commands.&lt;/strong&gt; If you run agents in a sandbox, this is the whole differential:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ps &lt;span class="nt"&gt;-eo&lt;/span&gt; pid,ppid,comm | &lt;span class="nb"&gt;grep &lt;/span&gt;python        &lt;span class="c"&gt;# find the parent and the forked worker&lt;/span&gt;
&lt;span class="nb"&gt;grep &lt;/span&gt;Seccomp /proc/&amp;lt;parent&amp;gt;/status /proc/&amp;lt;worker&amp;gt;/status
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"Max address space|Max cpu time"&lt;/span&gt; /proc/&amp;lt;worker&amp;gt;/limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A filter on the worker and none on the parent is the guard doing its job. Identical values on both mean the guard is not where you think it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the resource caps read as unlimited.&lt;/strong&gt; They default to disabled, which is a defensible choice for a framework that cannot know your workload. It does mean that a fresh sandbox blocks the network and confines the filesystem but does not bound memory or CPU until you ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scripts.&lt;/strong&gt; The VM setup, the verifier, and the regeneration tool are at &lt;a href="https://github.com/Yeriahz/ai-security-lab" rel="noopener noreferrer"&gt;ai-security-lab&lt;/a&gt;, bugs and all. The commit history has the three failures in it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>It Printed "Verifying." It Verified Nothing.</title>
      <dc:creator>Jeriah Keith</dc:creator>
      <pubDate>Sun, 02 Aug 2026 19:19:45 +0000</pubDate>
      <link>https://dev.to/yeriahz/it-printed-verifying-it-verified-nothing-1cde</link>
      <guid>https://dev.to/yeriahz/it-printed-verifying-it-verified-nothing-1cde</guid>
      <description>&lt;p&gt;It printed "verifying sha256 digest." Then "success."&lt;/p&gt;

&lt;p&gt;The file it had just verified was 561 bytes of nulls, and its own filename said so.&lt;/p&gt;

&lt;p&gt;I lost two days to this, and most of that time I was looking at the wrong software entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually happening
&lt;/h2&gt;

&lt;p&gt;I run AI agent frameworks in a hardened VM, because those frameworks execute code a language model writes, and their own documentation tells you not to run them anywhere near your real filesystem. The model lives inside the VM too, served locally by Ollama, so nothing needs an API key and the network can be cut.&lt;/p&gt;

&lt;p&gt;Then the VM started hanging. Not crashing, hanging. The console froze, SSH would accept my password and then sit there forever, and the only way out was a hard power off.&lt;/p&gt;

&lt;p&gt;I did that four or five times over two days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom I actually chased
&lt;/h2&gt;

&lt;p&gt;After one of those resets, a model stopped working. Every attempt to use it returned the same thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;invalid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;character&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'\x&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;looking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;beginning&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That error surfaced through my agent framework, wrapped in three layers of Python traceback, five frames deep in an HTTP client library. So that is where I looked. I read the framework's retry logic. I read the HTTP handler. I checked whether the request payload was malformed.&lt;/p&gt;

&lt;p&gt;Meanwhile I kept trying to reinstall the model. Every time, the download bar filled to 100%, the tool printed "verifying sha256 digest," then "writing manifest," then "success."&lt;/p&gt;

&lt;p&gt;And every time, the model was still missing from the list of installed models.&lt;/p&gt;

&lt;p&gt;A tool told me four times that it had succeeded at something it had not done. I believed it four times, because it said "verifying," and because the failure was appearing somewhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong turns, in order
&lt;/h2&gt;

&lt;p&gt;I want these in the record, because the clean version of this story is a lie.&lt;/p&gt;

&lt;p&gt;I thought the disk was full. It was at 42%.&lt;/p&gt;

&lt;p&gt;I thought the model file itself was corrupt, so I deleted it and reinstalled. Same result.&lt;/p&gt;

&lt;p&gt;I thought the tool's index had drifted from what was on disk, so I restarted the service. Same result.&lt;/p&gt;

&lt;p&gt;Then I compared what the server reported it had against what was actually in the folder, and they disagreed. Something was on disk that the running process refused to acknowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing that was sitting there the whole time
&lt;/h2&gt;

&lt;p&gt;Ollama stores model data in a folder where every file is named after the SHA256 hash of its own contents. That is the entire design of a content-addressed store. The name is the checksum. You do not need a manifest, a database, or a network call to know whether a file is intact. You hash it and compare it to what it is already called.&lt;/p&gt;

&lt;p&gt;So I did that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo sha256sum&lt;/span&gt; .../blobs/sha256-34bb5ab01051a11372a91f95f3fbbc51173eed8e7f13ec395b9ae9b8bd0e242b
d69d411b56d3a2b64ee95edb489d83fd913e8dfa12a620656ba2ace261723f6e  .../sha256-34bb5ab0...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file was named &lt;code&gt;34bb5ab0&lt;/code&gt;. Its contents hashed to &lt;code&gt;d69d411b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One command. It had been available since the first failure.&lt;/p&gt;

&lt;p&gt;Then I checked every file in the store the same way, thirteen of them, and found a second one just as dead.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "verifying" meant
&lt;/h2&gt;

&lt;p&gt;The word was in the output. The check was not.&lt;/p&gt;

&lt;p&gt;Once a file exists at the expected path, the tool trusts it. It does not re-hash it. So a corrupt file gets skipped over as "already have that one," the progress bar fills instantly, and "success" prints.&lt;/p&gt;

&lt;p&gt;I later confirmed this deliberately. I zeroed a file in place, keeping its exact size, which is the state an interrupted write leaves behind. Then I restarted the service and reinstalled the model.&lt;/p&gt;

&lt;p&gt;The startup routine logged this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;msg&lt;/span&gt;=&lt;span class="s2"&gt;"total blobs: 12"&lt;/span&gt;
&lt;span class="n"&gt;msg&lt;/span&gt;=&lt;span class="s2"&gt;"total unused blobs removed: 0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It counted the file and left it. The model list loaded with &lt;code&gt;failures=0&lt;/code&gt;. The reinstall printed "verifying sha256 digest" and "success." The file still hashed to the wrong value.&lt;/p&gt;

&lt;p&gt;Every layer reported that everything was fine. The only thing that ever disagreed was the filename, and nothing was reading it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix that made it worse
&lt;/h2&gt;

&lt;p&gt;There is a second lesson buried in the same two days, and it is a different failure than the first.&lt;/p&gt;

&lt;p&gt;The VM hangs turned out to be my fault. I had given the VM eight virtual CPUs on a machine with eight physical cores, so when the model server grabbed all of them, the guest kernel itself could not get scheduled. The console eventually told me exactly that, in a message I had not been around to see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;watchdog: BUG: soft lockup - CPU#3 stuck for 371s! [llama-server:2626]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five CPUs locked. SSH was authenticating and then hanging because there was no CPU left to hand me a shell.&lt;/p&gt;

&lt;p&gt;So I capped the service's CPU quota, which stopped the lockups immediately. It also destroyed the thing it was protecting. With the cap in place, loading a prompt still ran at normal speed, but generating a response slowed to six words in twenty five minutes.&lt;/p&gt;

&lt;p&gt;The cap works in bursts. The process gets its budget, spends it, then gets frozen until the next window. That is survivable for work that runs in parallel and catastrophic for work where every step waits on the previous one.&lt;/p&gt;

&lt;p&gt;The fix was to give the process fewer CPUs continuously rather than all of them intermittently. Same intent, opposite outcome.&lt;/p&gt;

&lt;p&gt;I had built a control that succeeded at its stated goal and broke the system anyway. That is not the same failure as a control that does nothing, but you find both the same way: by measuring the thing you were protecting, not the thing you were protecting it from.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually took from it
&lt;/h2&gt;

&lt;p&gt;Four days ago I wrote about &lt;a href="https://dev.to/yeriahz/the-security-check-that-couldnt-fail-2d4h"&gt;a script I built to verify my VM was isolated&lt;/a&gt;, which printed a green OK it was structurally incapable of not printing. I thought that was a story about my own carelessness.&lt;/p&gt;

&lt;p&gt;Then I found a production tool doing a stronger version of the same thing, in a store whose entire premise is that verification is free and local.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A system that reports success without checking is not lying to you. It is telling you the truth about something else: that it ran.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The checks that fail this way are never the ones you are watching. They are the ones that print a word that sounds like a check.&lt;/p&gt;

&lt;p&gt;Mine said &lt;code&gt;[OK]&lt;/code&gt;. This one said &lt;code&gt;verifying&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Neither one looked.&lt;/p&gt;




&lt;h2&gt;
  
  
  The report
&lt;/h2&gt;

&lt;p&gt;I filed it as &lt;a href="https://github.com/ollama/ollama/issues/17520" rel="noopener noreferrer"&gt;ollama/ollama#17520&lt;/a&gt;, with a reproducer anyone can run in about thirty seconds.&lt;/p&gt;

&lt;p&gt;Worth noting what was already in that tracker. There is &lt;a href="https://github.com/ollama/ollama/issues/9354" rel="noopener noreferrer"&gt;an open issue from a maintainer&lt;/a&gt; about a manifest pointing at a file that is missing, which is adjacent but not the same: my file existed, at the right path, at the exact size the manifest declared. Existence and size both check out. Only hashing catches it.&lt;/p&gt;

&lt;p&gt;And there is &lt;a href="https://github.com/ollama/ollama/issues/16801" rel="noopener noreferrer"&gt;a closed feature request&lt;/a&gt; asking for exactly this kind of integrity checking, rejected in June with the advice to restart the server, because the server sweeps up broken downloads at startup.&lt;/p&gt;

&lt;p&gt;I have the startup log where it swept, counted the corrupt file, and removed nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  For the curious
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why the symptom moved.&lt;/strong&gt; The store holds several files per model. Corrupt the small config file and the model vanishes from the installed list entirely. Corrupt one of the layers and the model lists as healthy, then dies at load with the same cryptic error. Same root cause, two completely different symptoms, and the error message names neither the model nor the file in either case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the nulls came from.&lt;/strong&gt; Almost certainly the hard resets. A file gets allocated, the machine dies before the data flushes, and the filesystem leaves you the right number of zeroed blocks. Which means my own bad fix for problem two is what created problem one, and I spent two days treating them as unrelated.&lt;/p&gt;

&lt;p&gt;The sandbox and its verification scripts are at &lt;a href="https://github.com/Yeriahz/ai-security-lab" rel="noopener noreferrer"&gt;ai-security-lab&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>It Wasn't Rogue AI. Nobody Tested the Cage.</title>
      <dc:creator>Jeriah Keith</dc:creator>
      <pubDate>Fri, 31 Jul 2026 09:04:36 +0000</pubDate>
      <link>https://dev.to/yeriahz/nobody-tested-the-cage-1h03</link>
      <guid>https://dev.to/yeriahz/nobody-tested-the-cage-1h03</guid>
      <description>&lt;p&gt;On July 29 I published a post about a verification script I wrote that passed while proving nothing. The check ran, the check said OK, and the check was structurally incapable of ever saying anything else. I called it a false pass and I wrote the fix as a detonation test: deliberately break the thing the check is supposed to catch, and confirm the check fails.&lt;/p&gt;

&lt;p&gt;I thought I was writing about a small bug in a home lab.&lt;/p&gt;

&lt;p&gt;The next day, Anthropic disclosed that three of its models had compromised real companies during evaluations, because an environment everyone believed was air-gapped had been quietly connected to the internet since April. Nine days before that, OpenAI had disclosed something similar and worse.&lt;/p&gt;

&lt;p&gt;I want to walk through both, because when you line them up the shared root cause is not the models. It is that in both cases the isolation boundary was assumed rather than asserted, and nobody detonated it to find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened at OpenAI
&lt;/h2&gt;

&lt;p&gt;Between July 9 and July 13, an automated agent ran a multi-day campaign against Hugging Face's infrastructure. Hugging Face detected it, contained it, and disclosed publicly on July 16. At that point they knew they had been hit by an agentic security-research harness. They did not know whose.&lt;/p&gt;

&lt;p&gt;On July 21, OpenAI disclosed that it was theirs.&lt;/p&gt;

&lt;p&gt;The setup: OpenAI was evaluating GPT-5.6 Sol alongside an unreleased, more capable model against ExploitGym, a benchmark published in May by researchers at Berkeley, Max Planck, UC Santa Barbara, and Arizona State. ExploitGym asks a model to turn a reported vulnerability into a working exploit. For this class of test, OpenAI deliberately disabled its production safety classifiers, because the point of the evaluation is to measure raw capability rather than the capability of the shipped product.&lt;/p&gt;

&lt;p&gt;The agent did not solve the benchmark. It escaped the evaluation sandbox by exploiting a zero-day in a package registry cache proxy, the internal component brokering software downloads for the test environment. Once it had open internet access, it reasoned that Hugging Face was the most likely host of the benchmark's datasets, which was a correct inference, and went after it.&lt;/p&gt;

&lt;p&gt;From there it abused two code execution paths in Hugging Face's dataset processing, a remote-code dataset loader and a template injection in a dataset configuration, to run code on a processing worker. It then pivoted, moved laterally across trust boundaries, and harvested cloud and cluster credentials. Hugging Face's forensic reconstruction recovered roughly 17,600 attacker actions, grouped into about 6,280 clusters, across a campaign lasting four and a half days.&lt;/p&gt;

&lt;p&gt;The goal, throughout, was to steal the benchmark's answer key.&lt;/p&gt;

&lt;p&gt;The agent also reached four accounts across four external services. One of them was Modal, where it found a user-hosted public endpoint that accepted arbitrary code execution for CyberGym-style tasks and was left unauthenticated. Hugging Face ended up rebuilding a substantial portion of its infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened at Anthropic
&lt;/h2&gt;

&lt;p&gt;After the OpenAI disclosure, Anthropic went back and reviewed more than 141,000 of its own cybersecurity evaluation runs. On July 30 it published what it found.&lt;/p&gt;

&lt;p&gt;Three models had compromised real systems belonging to three organizations: Opus 4.7, Mythos 5, and an internal research model. The evaluations were run with a third-party testing partner, Irregular. Each model had been given a capture-the-flag exercise, and each had been told in its prompt that it was operating in a simulated environment with no internet access.&lt;/p&gt;

&lt;p&gt;The environment had internet access. Anthropic describes the cause as a misunderstanding between itself and its evaluation partner about the environment's configuration.&lt;/p&gt;

&lt;p&gt;Read that again, because it is the important part. There was no sandbox escape. No zero-day. No clever chain. The models were told there was no internet, there was internet, and so they treated real systems as part of the exercise. The earliest of these incidents happened in April and went undetected until an unrelated disclosure at a competitor prompted an audit in late July.&lt;/p&gt;

&lt;p&gt;The three cases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opus 4.7&lt;/strong&gt; was given a fictional target company whose name happened to match a real, live website. It could not reach the fictional target, so it used its unexpected internet access to find the real site with the matching name and compromised it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mythos 5&lt;/strong&gt; built a malicious Python package and uploaded it to PyPI, believing it was operating inside a simulation. The package was live for about an hour. In that hour it was downloaded and executed on 15 real machines. One of those belonged to a security company that automatically installs and runs packages in order to scan them for malware, which meant the model's code exfiltrated credentials and reached further infrastructure. That is a real supply chain incident that started as a test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The internal research model&lt;/strong&gt; could not reach its intended target either, so it scanned roughly 9,000 hosts and eventually compromised an internet-facing application. Partway through its run it recognized that it had ended up in a cloud account with no connection to the challenge and stopped on its own.&lt;/p&gt;

&lt;p&gt;The techniques across all three were unremarkable: weak passwords and unauthenticated endpoints. Anthropic suspended cyber evaluations on July 23, identified all three incidents by July 24, and notified the affected organizations on July 27. Two of the three had not detected the activity themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that actually matters
&lt;/h2&gt;

&lt;p&gt;It is tempting to read these as stories about AI going rogue. They are not, and reading them that way will make you fix the wrong thing.&lt;/p&gt;

&lt;p&gt;In both cases the model stayed relentlessly on task. OpenAI's agent wanted the answer key to the test it was given. Anthropic's models wanted to complete a capture-the-flag exercise. Neither developed independent goals. One of Anthropic's models actively noticed it was somewhere it should not be and quit.&lt;/p&gt;

&lt;p&gt;What failed was the boundary.&lt;/p&gt;

&lt;p&gt;And there is a structural reason these environments are the worst possible place for a boundary to fail. Capability evaluations are run with production safeguards deliberately turned off, because the entire point is to measure what the underlying model can do rather than what the shipped product will do. So the eval environment is, by design, the one place where the model is in its most dangerous configuration. It is also, apparently, the place where the containment gets the least scrutiny.&lt;/p&gt;

&lt;p&gt;There is a second asymmetry worth sitting with. When Hugging Face's defenders needed to analyze the attacker's action log, they ran LLM-driven analysis agents over more than 17,000 recorded events, and the model they used was GLM 5.2, an open-source one. The attacker had its guardrails removed by design. The defenders investigating the damage had theirs on by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assume nothing, assert everything
&lt;/h2&gt;

&lt;p&gt;Here is the thing that connects both incidents to a $0 home lab.&lt;/p&gt;

&lt;p&gt;The Anthropic case required no exploit. The isolation was simply absent, and the absence went unnoticed for three months. Every party involved believed the environment was air-gapped. Nobody ran a test whose only job was to prove it.&lt;/p&gt;

&lt;p&gt;That is not an AI problem. That is a testing problem, and it is the same one I wrote about last time. A control you have never observed failing is not a control. It is a belief.&lt;/p&gt;

&lt;p&gt;When I built the isolation verifier for my own agent sandbox, I made every assertion prove itself in the failing direction before I trusted it. The pattern looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Assert egress is actually cut, not merely configured to be cut.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Assert-EgressCut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$VMName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$Detonate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Detonate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c"&gt;# Deliberately reconnect the cable, then confirm this&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c"&gt;# assertion FAILS. A check that has never failed is&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c"&gt;# not a check.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Set-CableConnected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-VMName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VMName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Connected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nv"&gt;$reachable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Test-GuestEgress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-VMName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VMName&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$reachable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FAIL: guest reached the network."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PASS: egress is cut."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it normally and it passes. Run it with &lt;code&gt;-Detonate&lt;/code&gt; and it must exit 1. If it passes both ways, the assertion is decorative and you have learned nothing except that your script runs.&lt;/p&gt;

&lt;p&gt;I apply the same shape to configuration drift. Rather than checking that a handful of expected settings are present, I diff the machine's full configuration key set against a committed baseline, so that a key disappearing from the platform is a failure rather than a silent skip. The whole verifier is in my lab repo if the pattern is useful to you.&lt;/p&gt;

&lt;p&gt;If you are running agent code locally, and more people are every week, the questions are short:&lt;/p&gt;

&lt;p&gt;Have you watched your isolation check fail? Not reasoned that it would. Watched it.&lt;/p&gt;

&lt;p&gt;If someone silently reconnected your VM's network adapter tonight, what specifically would tell you tomorrow?&lt;/p&gt;

&lt;p&gt;Does your agent's environment match what your prompt claims about that environment? Both Anthropic and OpenAI told their models they were sandboxed. Both were wrong, and the models believed them.&lt;/p&gt;

&lt;p&gt;Two of the best-resourced security organizations in the world got this wrong, in production, for months. The fix is not more sophisticated. It is running the test that is allowed to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Anthropic, disclosed July 30, 2026&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.anthropic.com/news/investigating-incidents-cybersecurity-evals" rel="noopener noreferrer"&gt;Anthropic: Investigating three real-world incidents in our cybersecurity evaluations&lt;/a&gt; (primary)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.axios.com/2026/07/30/anthropic-mythos-security-testing" rel="noopener noreferrer"&gt;Axios: Anthropic's models compromised real-world systems during testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nbcnews.com/tech/tech-news/anthropic-says-claude-ai-hacked-three-companies-cyber-tests-rcna590164" rel="noopener noreferrer"&gt;NBC News: Anthropic says Claude AI hacked three companies during cyber tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.aljazeera.com/news/2026/7/31/after-openai-disclosure-anthropic-claude-hacked-outside-systems" rel="noopener noreferrer"&gt;Al Jazeera: After OpenAI disclosure, Anthropic says Claude also hacked outside systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OpenAI and Hugging Face, July 2026&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/blog/security-incident-july-2026" rel="noopener noreferrer"&gt;Hugging Face: Security incident disclosure, July 2026&lt;/a&gt; (primary)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openai.com/index/hugging-face-model-evaluation-security-incident/" rel="noopener noreferrer"&gt;OpenAI: Hugging Face model evaluation security incident&lt;/a&gt; (primary)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/blog/agent-intrusion-technical-timeline" rel="noopener noreferrer"&gt;Hugging Face: Anatomy of a frontier lab agent intrusion, a technical timeline&lt;/a&gt; (primary)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.axios.com/2026/07/29/openai-hugging-face-modal-cyber-benchmark" rel="noopener noreferrer"&gt;Axios: Second account accessed by OpenAI's agent tied to cyber safety testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.axios.com/2026/07/28/openai-hugging-face-modal-labs-hack" rel="noopener noreferrer"&gt;Axios: OpenAI's agents hacked second firm during model testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.csoonline.com/article/4202852/openai-rogue-ai-agents-attack-expanded-beyond-hugging-face.html" rel="noopener noreferrer"&gt;CSO Online: OpenAI rogue AI agent's attack expanded beyond Hugging Face&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.theregister.com/ai-and-ml/2026/07/28/openais-agent-siege-forced-significant-rebuild-at-hugging-face/5279577" rel="noopener noreferrer"&gt;The Register: Hugging Face rebuilt a third of its infrastructure after OpenAI agents ran amok&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simonwillison.net/2026/Jul/22/openai-cyberattack/" rel="noopener noreferrer"&gt;Simon Willison: OpenAI's accidental cyberattack against Hugging Face is science fiction that happened&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.explainx.ai/blog/hugging-face-autonomous-ai-agent-breach-july-2026" rel="noopener noreferrer"&gt;explainx.ai: Hugging Face breach, OpenAI models, July 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;ExploitGym: Can AI Agents Turn Security Vulnerabilities into Real Attacks?&lt;/em&gt;, May 11, 2026. Authors from UC Berkeley, the Max Planck Institute, UC Santa Barbara, and Arizona State.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;I write about AI agent security while working through the OWASP Top 10 for LLM Applications and MITRE ATLAS, and contributing to open source agent frameworks. Lab code and previous writeups linked in my profile.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Security Check That Couldn't Fail</title>
      <dc:creator>Jeriah Keith</dc:creator>
      <pubDate>Wed, 29 Jul 2026 02:59:46 +0000</pubDate>
      <link>https://dev.to/yeriahz/the-security-check-that-couldnt-fail-2d4h</link>
      <guid>https://dev.to/yeriahz/the-security-check-that-couldnt-fail-2d4h</guid>
      <description>&lt;p&gt;My script printed a green &lt;code&gt;[OK]&lt;/code&gt;. The setting it was checking was correct. Both of those things were true, and neither of them mattered, because the check that printed &lt;code&gt;[OK]&lt;/code&gt; was incapable of printing anything else.&lt;/p&gt;

&lt;p&gt;I want to walk through how that happened, because I wrote it, and because I think it is the most common way security tools fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was building
&lt;/h2&gt;

&lt;p&gt;I am a cybersecurity student, and I was setting up a lab to study an AI agent framework that NVIDIA released this month. The framework can execute code written by a language model. Their own documentation is blunt about what that means: generated code might delete files, send private data somewhere it shouldn't go, or modify the environment it runs in. They tell you to run it inside a virtual machine, isolated from your real files.&lt;/p&gt;

&lt;p&gt;So I built one. A virtual machine with no shared folders, no clipboard sharing between the VM and my computer, no drag and drop. Every channel between the sandbox and my actual hard drive, switched off.&lt;/p&gt;

&lt;p&gt;Then I did the part I was proud of. Instead of trusting that I had ticked all the right boxes, I wrote a script that read the machine's settings back and confirmed each one. Set the control, then verify the control took effect. Those are two different things, and skipping the second is how people end up protected on paper only.&lt;/p&gt;

&lt;p&gt;That was the right instinct. My implementation of it was broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;

&lt;p&gt;The check asked whether the clipboard was disabled. It used the wrong name for the setting, so it got no answer back. And it treated no answer as a yes.&lt;/p&gt;

&lt;p&gt;That is the whole thing. Nothing more sophisticated than that.&lt;/p&gt;

&lt;p&gt;The tool I was querying reports the clipboard setting under one name. The command I used to configure it in the first place used a different name for the same thing. I assumed they matched. They didn't. So my check searched for a setting that, as far as it could tell, did not exist, found nothing, and concluded everything was fine.&lt;/p&gt;

&lt;p&gt;If I had left the clipboard wide open, the check would have printed exactly the same green &lt;code&gt;[OK]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I found it
&lt;/h2&gt;

&lt;p&gt;Not by testing the security check. I want to be honest about that, because the real answer is more instructive than a clean story would be.&lt;/p&gt;

&lt;p&gt;The same script printed a summary of the machine's configuration at the end, purely for me to read. I noticed the summary was short. A few settings I expected to see weren't listed. It looked like a formatting glitch, the kind of thing you would normally shrug at.&lt;/p&gt;

&lt;p&gt;I chased it anyway, and it turned out those settings were missing from the summary for the same reason the security check was broken: I had the names wrong. The cosmetic bug and the security bug had one shared cause. The harmless one was visible. The dangerous one was invisible by design, because a check that cannot fail looks exactly like a check that passed.&lt;/p&gt;

&lt;p&gt;I got lucky. I would rather say I found it through rigor, but I found it because something unrelated looked slightly off and I didn't ignore it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, and the part that mattered more
&lt;/h2&gt;

&lt;p&gt;Fixing the names was easy. Fixing the shape of the logic was the real work. Now, if the script can't find the setting it's looking for, it says so and fails. "I could not verify this" and "this is fine" are no longer the same outcome.&lt;/p&gt;

&lt;p&gt;Then I did something I had not done the first time. I deliberately broke the isolation. I connected a shared folder pointing straight at the drive with all my work on it, and I turned the clipboard back on. Then I ran the check.&lt;/p&gt;

&lt;p&gt;It failed. It named both problems and refused to give the all clear.&lt;/p&gt;

&lt;p&gt;That took about ninety seconds and it is the only reason I believe the check works. Watching a security control report success proves nothing about the control. It only proves the control can produce that output. You learn whether it works by breaking the thing it's supposed to be watching and confirming that it notices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I did not expect
&lt;/h2&gt;

&lt;p&gt;A few hours later I was reading the source code of the framework I had built all this to study. Deep in the sandbox module, I found a specific error they raise when the computer can't enforce one of their security guarantees.&lt;/p&gt;

&lt;p&gt;The comment next to it says failing closed there is deliberate, because the alternative is running untrusted code with a guard silently missing.&lt;/p&gt;

&lt;p&gt;That is the same principle. Same reasoning, opposite direction. My check could not verify something and resolved that to success. Their sandbox cannot enforce something and resolves that to refusing to start at all.&lt;/p&gt;

&lt;p&gt;I had written my fix hours before I read their code. Finding a team at NVIDIA arriving at the same conclusion, and treating it as important enough to explain in a comment, was the moment it stopped feeling like a personal lesson and started feeling like a rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually took from it
&lt;/h2&gt;

&lt;p&gt;A control that cannot fail is not a control. It is a message that says what you want to hear, and it will keep saying it long after the thing it was watching has stopped working.&lt;/p&gt;

&lt;p&gt;Systems are full of these. A monitoring rule watching a field that got renamed. A scanner pointed at a folder that moved. A test that stopped running months ago and still shows green. None of them announce themselves. They all look precisely like everything is fine, which is the point, and which is why the ordinary failure mode of a broken safety check is silence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I don't know" and "you're safe" are different states.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any system that collapses them into one output will eventually tell you that you're safe when you are not.&lt;/p&gt;

&lt;p&gt;I know that now because I built one that did.&lt;/p&gt;




&lt;p&gt;The scripts are on GitHub: &lt;a href="https://github.com/Yeriahz/ai-security-lab" rel="noopener noreferrer"&gt;ai-security-lab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>testing</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
