Eight Months of Security Infrastructure for AI Agents

My last post was September 5, 2025. It is now May 2026. That is eight months of radio silence on this blog — not eight months of nothing, but eight months of heads-down building without stopping to write about it.

I am not going to pretend the gap is smaller than it is. The honest version is that I got absorbed in a cluster of security projects and skipped the blogging. The portfolio restructure I just finished surfaced the full picture clearly for the first time, and it is worth telling the story properly rather than letting it disappear into a list of repo names.

The through-line across all of it is security and economic infrastructure for AI agents and for people who want to operate without accounts, without servers, and without trusting intermediaries. Three theme arcs: tooling for AI agents to reason about sources and route payments, privacy tooling for humans who want to move data without a central operator, and network-layer defenses for the environments agents run in. Here is what I built.


AI-Agent Infrastructure

Agents have access to the whole web and have no real economic identity of their own. Two of the projects in this arc address those gaps directly; the third builds a payment and routing layer underneath them.

3goodsources — A Trust Registry for AI Agents

AI agents can retrieve any document on the web, but most of what they retrieve is noise: SEO-gamed listicles, blog posts that copy other blog posts, affiliate links dressed up as recommendations. The problem is not access — it is that agents have no quality signal. They cannot tell the official Bitcoin Core documentation from a random Medium post ranked third because of SEO tricks.

3goodsources is an MCP server that gives AI agents access to a human-curated trust registry. A curator researches a topic, picks exactly three trusted sources — official docs, best tutorial, essential tool — and signs those recommendations cryptographically via PKARR. The "three sources" constraint is deliberate: it forces ruthless prioritization and makes the curation effort sustainable.

Any MCP-compatible agent can query the registry with a natural-language phrase ("learn rust", "set up a bitcoin full node") and get three ranked, signed sources back — no search engine, no pagerank. The query matcher uses fuzzy Levenshtein scoring so phrasing differences do not break the lookup. Built in Rust. The registry is public and inspectable.

Claude Code sessions are machine-local. If you start a session on your desktop and want to pick it up on a laptop or a remote machine, the workflow breaks. Claude Code's native remote control feature exists but depends on Anthropic accounts. cclink handles this differently.

Your Ed25519/PKARR keypair is your identity. The Mainline DHT is the rendezvous. cclink encrypts the session ID, signs it, and publishes a PKARR SignedPacket to the DHT. On another machine, cclink pickup resolves, verifies the dual Ed25519 signatures, decrypts, and runs claude --resume automatically. No accounts, no central relay, no signup tokens. The session ID, hostname, and project path are inside the encrypted payload; the DHT sees only opaque bytes.

Three encryption modes cover different scenarios: self (only you can pick up), shared (specific recipient's public key), and PIN (Argon2id-derived shared secret, no key exchange needed). Any combination of modes can be combined with --burn for single-use handoffs.

arbstr — LLM Routing with Bitcoin Settlement

LLM inference pricing on decentralized marketplaces like Routstr is inconsistent. Provider A charges 8 sats per 1k tokens. Provider B charges 12. Provider C charges 10. The spreads are real and exploitable with a basic routing algorithm. The deeper problem is that AI agents have no native economic identity — no per-agent spend metering, no budget enforcement, no audit trail.

arbstr is a three-part stack that solves both problems. arbstr core is a Rust routing proxy with an OpenAI-compatible API that automatically selects the cheapest qualified provider per request, with circuit breakers and a policy engine for routing rules. arbstr-vault is a TypeScript treasury service that gives each agent an isolated sub-account with a reserve/settle/release billing cycle backed by SQLite, settles in Lightning or Cashu, and fails closed on over-limit transactions. arbstr-node is a Docker Compose deployment layer that starts the full stack — proxy, vault, LND, Cashu mint — with a single command.

Even without sophisticated routing heuristics, just selecting the cheapest provider at request time saves 20-30 percent on inference costs. The vault side is experimental — the architecture is correct in principle, but "correct in principle" and "safe with real funds" are not the same thing, and the README says so explicitly.


Accountless Privacy and Pubky

This arc is a cluster of tools for moving data and money between parties without a server, without an account, and without trusting any central operator. PKARR and the Mainline DHT appear in all three projects as the rendezvous layer. The cryptographic stacks overlap.

cipherpost — Serverless Cryptographic Material Handoff

Moving SSH keys, X.509 certificates, PGP keys, or generic secrets between parties is painful in practice despite being a solved problem in theory. Common solutions involve standing up shared infrastructure or routing through services that have subpoena surfaces: S3 buckets, email attachments, Slack DMs, secrets managers with accounts.

cipherpost makes the transfer accountless, serverless, and verifiable. Your PKARR keypair is your identity. The Mainline DHT is the rendezvous. The payload is age-encrypted and dual-signed — outer PKARR signature and inner Ed25519 signature over canonical JSON. The recipient sees an acceptance screen showing the sender's fingerprints, purpose, TTL, and payload type before any decryption runs. To confirm, they type the sender's z-base-32 pubkey. The receipt is published back to the DHT so the sender can verify delivery without a central log.

cipherpost and cclink share a cryptographic stack (PKARR, age, Argon2id, dual signatures). They diverge at the payload: cclink carries a Claude Code session ID; cipherpost carries typed cryptographic material with an explicit acceptance step and signed receipts.

blindjoin — CoinJoin with Cryptographic Unlinkability

CoinJoin improves Bitcoin transaction privacy by combining multiple participants' inputs and outputs into a single transaction, breaking the chain-analysis assumption that inputs and outputs belong to the same owner. The bottleneck is the coordinator — the entity that assembles the transaction can see which input registered which output.

blindjoin closes that gap with RSA blind signatures (RFC 9474). Participants submit their output addresses in blinded form. The coordinator signs the blinded token without seeing the underlying address. The participant unblinds the signature and uses it to register their output. The coordinator issued the credential and later verifies it, but the two events are mathematically unlinkable. It cannot determine which input produced which output even if it tries.

All round traffic runs over Tor hidden services using arti-client. Coordinator discovery uses the PKARR DHT — no hardcoded addresses. Per-phase circuit isolation means the coordinator cannot correlate input and output registration by Tor circuit. The full Docker Compose stack (bitcoind signet, coordinator, liquidity bot) runs locally for development. Fixed-denomination rounds on signet; not production-ready with real funds.

PKTap — NFC Contact Exchange Without Servers

Sharing contact information on phones currently means trusting an intermediary. AirDrop requires an Apple account. QR codes send plaintext. Bluetooth contact exchange apps route through servers.

PKTap uses the hardware already in both phones — NFC — to bootstrap a key exchange. Two phones tap via Android HCE. ECDH derives a shared secret. Contact fields are encrypted with XChaCha20-Poly1305 and published to the Mainline DHT at a deterministic address (SHA-256 of the sorted pair of public keys). The other device resolves and decrypts. The architecture is split cleanly: Rust handles all cryptographic operations; the Android app handles UI and NFC via a UniFFI bridge. The master key is non-extractable from the Android Keystore under StrongBox or TEE.

PKTap is v1.0 with 5 of 7 phases complete — the cryptographic core and NFC subsystem work; full app UI is still in progress.


Network and DNS-Layer Defense

The third arc focuses on the environments that AI agents run in: the web pages they browse and the domains they reach out to. Both projects in this arc are about measurement and pre-fetch filtering.

HoneyPrompt — AI Agent Compliance Testing

AI browsing agents are deployed against real web infrastructure, and there is limited tooling to measure how they behave when they encounter prompt-injection instructions from untrusted content. Without evidence, threat modeling for product security teams is guesswork.

HoneyPrompt generates honeypot web pages with hidden prompt-injection canaries embedded across multiple locations: HTML comments, meta tags, invisible span elements, JSON-LD structured data, and natural-language prose. When an AI agent visits the page and follows the injected instructions, it makes an HTTP callback. The five-tier graduated evidence model measures increasing levels of compliance: arbitrary callback, conditional callback, computed callback, capability introspection, and multi-step compliance chain. Each tier provides independently verifiable evidence without touching secrets or credentials.

The honeyprompt test-agent subcommand runs a self-contained compliance test for CI pipelines — a scorecard with a pass/fail exit code. The single Rust binary with a --domain flag starts serving immediately from a tempdir. Caddy + Docker Compose is available for production deployments.

agent-dns-firewall — In-Process Domain Blocking for AI Agents

AI agents make network requests, and most agent frameworks let everything through by default. Adding a domain-level blocklist check before fetch() is simple in principle and surprisingly absent in practice. DNS servers and HTTP proxies add infrastructure; an in-process library adds a function call.

agent-dns-firewall is an npm library. Before your agent calls fetch(), call isDomainBlocked(hostname). It downloads StevenBlack's unified hosts file and Hagezi's DNS light list, builds an in-memory index with subdomain matching, and auto-refreshes with conditional HTTP headers (ETag, If-Modified-Since) so a long-running agent process does not stale out. Zero runtime dependencies. Synchronous check. Works with any HTTP client or framework.

The BlockDecision return type — blocked, reason, listId — provides enough context for logging and auditing, not just for silently dropping requests.


What's Next

The portfolio restructure is done and the blog is current again. The immediate next step is finishing the per-project write-ups for each of these projects — deeper posts on the specific protocol decisions, the tradeoffs, and what still needs work. PKTap's remaining two phases (app UI, QR fallback) are on the roadmap. The arbstr-vault hardening work — real audit, real threat model, real fund handling — is the gap between "correct in principle" and "deployable."

The broader theme is not going away. AI agents need infrastructure that treats them as economic and security principals, not just API consumers. The security of the environments they operate in needs measurement, not just aspiration. That is the work.


Eight months in, the portfolio finally tells the story I was trying to build toward.