Category Archives: Security

Migrate to 44 Now or Get Quantum Cracked

Raise your bloodied hand missing fingers if you lived through SHA-1 deprecation. What about 3DES?

For those who don’t remember, Xiaoyun Wang, Yiqun Lisa Yin & Hongbo Yu published the collision attack in 2005. Google’s ad-revenue funded deep bench of engineers produced a working collision in 2017. The twelve miserable years between them were filled with noise about why the sunset timeline was unrealistic. Standards bodies ran interop events that nobody implemented, and CAs kept selling SHA-1 certs until the registrars stopped taking them. Banks, proving the old adage that privilege and power make you stupid, kept shipping SHA-1 internal certs long into 2019.

The cryptanalysts were not wrong. The institutions were not on time, because they aren’t funded by advertising and so they have to mind actual margins. The margin managers push back on deadlines because pushing back is cheaper than protecting customers.

Fun fact, PCI DSS has always been about payment card brands whacking banks with a huge stick to get them to upgrade consumer safety. 2016 was the absolute deadline for TLS v1.0 deprecation and banks cried a tidal wave that pushed it back all the way to 2018. Bad for you, bad for me, good for bank margins.

Anyway, my beard is grey enough already. Let’s talk about today. The same pattern is playing out again, only the deadlines are shorter and the damage is worse. The cryptanalysts are publishing. The institutions are dragging. The vendors are hedging. Pour one out to my colleagues already six feet under, who no longer have the pleasure of rotating keys.

Filippo Valsorda is the bellwether. Two years ago he was the guy telling everyone to ship Kyber hybrids. This month he is telling everyone to skip hybrid signatures. Done. Dusted. Your window closed.

It’s pure ML-DSA-44 or nothing.

Today I’m here to tell you that anything still negotiating classical-only key exchange in 2026 should from this point forward be treated as a potential active compromise. I am not saying “future risk.” This isn’t “areas for improvement.”

Active. Compromise.

As in, assume someone is sitting in your traffic right now and is going to read it later like you didn’t protect it, because you didn’t.

The reason hybrid signatures just blew up is the vendors invested in the wrong insurance. Eighteen composite key types in the IETF draft. Sixteen revisions of the spec already, with another year of revisions to come. Wire format negotiation. Certificate chain handling. Years of vendor work, then years of operator work, all to hedge against the possibility that ML-DSA gets classically broken before the quantum computers arrive.

It’s an interesting game. Watching the world’s best cryptanalysts beating on ML-DSA for eight years has produced nothing. It is still running like a champ. The hedge is looking more and more like a gamble that failed.

Meanwhile classical key exchange is cooked. Stick a fork in it. I’ve been warning CISOs on hundreds of calls for the last year that 2027 would be a shitshow if they didn’t get prepared for what’s coming. Google’s internal PQ deadline now is officially 2029. We’re looking at a fuse just 33 months long. Google Quantum AI published in March that the resources to break secp256k1 fit under 500,000 physical qubits with runtime measured in minutes. The Chevignard, Fouque, and Schrottenloher paper at EUROCRYPT 2026 cut the logical qubit count for breaking P-256 nearly in half, from 2,124 down to 1,193. The numbers that mattered six months ago no longer apply. ECC breaks first because its smaller keys need fewer qubits. RSA breaks second. The most exposed thing on your network is your modern X25519/ECDSA stack, not some legacy RSA box gathering dust bunnies in the corner. OpenSSH put a warning on non-PQ key agreement in the last release, the same way they warn on self-signed certs and weak passwords.

That’s actual real-world urgency.

Constant monitoring of the NIS2 sectors for Quantum preparedness has unlocked a ton of key management insights. Ask me anything.

The German BSI requires hybrid for both KEX and signatures. The French ANSSI requires hybrid for both. And the American NIST is somewhere in the middle, slow-walking a hybrid mandate while industry lobbying keeps it stuck in voluntary guidance. The Anthropic cartel is leading that effort.

I’m reading an IETF draft 16 of the composite signatures spec while the engineer who built the original Kyber hybrids is saying forget it. Too late. Wrap it up.

This sucks for those of us trying to run an operation because every scanner will grade the same TLS endpoint differently depending on which way an authority blows.

Welcome back to the stupidity of the SHA-1 transition, only with deadlines shaved down six years and consequences a lot worse than a forged certificate. The breach already happened. Someone is soaking up your traffic now. They read it when their qubits arrive.

I wrote some of this up in plain mode on [PQ]probe so you can share it at work:

The hybrid signature split: Filippo Valsorda has reversed his position on hybrid signatures: pure ML-DSA-44 is fine for sigs, hybrid stays for KEX, non-PQ KEX is a potential active compromise. The shift puts BSI’s hybrid mandate and the new Geomys/OpenSSH posture on a collision course. Scanners will need to report against both.

Three things to do this week. Drop classical-only key exchange yesterday. Ship X25519MLKEM768 hybrid for KEX. Ship pure ML-DSA-44 for signatures. Change pants.

Sorry, four things.

Since your remaining 33 months are going to be half that by the time budget approval stops fixating on AI nonsense, I made [PQ]probe as comprehensive, cheap and easy as possible. Mind the handshake size change. You can use our PQ calculator to see what hits the wire.

A Berlin, Germany official called me an “artfremd” (alien) to my face and told me to go back where I came from so many times, I made it our logo.

Grab your probe, get on 44 now or get cracked.

How Robert E. Lee Laundered His Rapes and Black Children

An 1865 newspaper article reported that Robert E. Lee’s wife had forty mixed-race half-siblings living in the Washington, D.C. area. Forty. Her father had acknowledged at least one of them, Maria Carter Syphax, to her face. Her husband managed the household, the plantations, and the estate for decades.

The official record says Lee fathered seven children. The country of Trump-Epstein historiography permits no more.

This is what record laundering looks like.

And here’s a thought I want you to hold in mind as you read this post: Lynching got measured because perpetrators wanted it measured. Postcards, newspaper accounts, public spectacle, named participants. The phenomenon was performed for the record. The Tuskegee dataset and EJI’s later compilations of lynchings could exist because the underlying acts were always run as celebrations. Rape of Black women was the inverse architecture. A private prerogative, denied even by those who exercised it, rarely prosecuted, never aggregated except in large receipts from selling Black children into human trafficking markets.

Enslaved Black women who were being systemically erased, denied records, had no legal recourse against rape by white men.

The formal opening of the courts after emancipation produced negligible prosecution for the next century. Crystal Feimster locates the only meaningful procedural opening at the Civil War military justice system, where Lincoln’s Lieber Code defined wartime rape as a crime and produced the first record of Black women bringing charges. Civilian state courts remained closed in practice.

The lynching of Black men on rape charges was a deflection device that protected white-male rape of Black women. Rape was the prerogative. Lynching was the policing tool that defended the prerogative by displacing the accusation.

Household of Rape

George Washington Parke Custis built Arlington House as a shrine to the man who raised him. He filled it with enslaved labor inherited from Mount Vernon. He enslaved his own children. He fathered children with the women he enslaved.

The Mount Vernon Ladies’ Association states the matter plainly. Custis was commonly believed to have fathered children by enslaved women in his possession. Those children were often freed or singled out for special treatment. He acknowledged Maria Carter Syphax to her face. He is also believed to have fathered a girl named Lucy with the enslaved woman Caroline Branham. The 1865 newspaper claim of forty Washington-area half-siblings to Mary Custis Lee is not Black family folklore. It is contemporary white print.

This was the household Robert E. Lee married into in 1831.

He took it over as Custis’s executor in 1857. He ran it through 1862. He inherited the moral economy along with the property. In Lee’s world, fathering children with the enslaved women of one’s own household was already understood as a feature of upper-class Virginia plantation life. The maid who served Mary Custis Lee was Mary Custis Lee’s half-sister. Both women lived in that arrangement. So did Lee.

The Monster

Lee owned people with intent. He chased them when they ran. He returned them to bondage. In 1859 he ordered Wesley Norris whipped fifty lashes after Norris escaped and was recaptured. He called for brine to be poured on the wounds. Norris’s testimony was published in 1866.

Most notably the Lost Cause apparatus forcibly suppressed evidence such as this for over a century until Elizabeth Brown Pryor’s Reading the Man (2007) and Michael Fellman’s earlier work cracked the Lee edifice and re-established it.

In his 1865 letter to Andrew Hunter, Lee defended slavery as the optimal arrangement between the races so long as it operated under what he considered humane law and Christian influence. He cast Black subjugation as his divinely ordered tutelage. He believed enslaved people were better off in his bondage than free. He understood slavery as his right to inflict discipline, religiously sanctioned, strictly enforced.

A man capable of ordering brine in fresh whip wounds was more than capable of raping the women he “divinely” controlled. The question is whether the social structure he inhabited, the household he managed, and the women who were his constant hostages produced what such structures produce everywhere they exist.

The structure was not exceptional. After Congress banned the international slave trade in 1808, the reproductive labor of enslaved women became the plantation economy’s growth engine. Rape produced children. Children produced sale. Sale produced profit. The bodies of enslaved women were the commodity factory. The output, the historiography insists, was exceptional.

Say Rape

The vocabulary matters. Liaisons. Relationships. Concubinage. Mistresses. These are euphemisms drafted later by white historians of the white South to describe coercion they would not name. Enslaved women had no legal personhood and no capacity to consent. The act under conditions of total ownership is sexual violence. The record-keeping vocabulary that softens it is part of the laundering.

Hilberg’s stages of destruction begin with definition. Definition determines what counts. Every word that reduces a forced act to a chosen one is a small architectural choice in the larger structure of denial.

Laundering of Rapist Lee

Three mechanisms.

Archival capture. The Lee papers concentrate at Washington and Lee University, the Virginia Museum of History and Culture, and Stratford Hall. These institutions were curated for a century by only Lee descendants and Lost Cause partisans. Douglas Southall Freeman’s 1934 Pulitzer biography set the canon with family cooperation. Honest material was weeded before it ever entered processing, to curate a fiction. When Pryor finally accessed previously unpublished family papers in the 2000s, what she surfaced reframed Lee on slavery, on family conflict, and on his treatment of the enslaved. She did not find paternity evidence. The honest reading is that paternity evidence, had it ever been written down, was the first thing weeded.

Evidentiary asymmetry. White genealogies pass on parchment. Black claims of white paternity require DNA, court records, and corroborating witnesses to count. Family Bibles recorded white births. Plantation books logged enslaved births in separate columns, usually without paternity. And of course we know America’s historical profession was overwhelmingly white and male until the 1970s, with Ulrich Phillips’s apologetic frame dominant until Kenneth Stampp, and treated enslaved testimony as inherently unreliable. After emancipation the one-drop rule incentivized passing, which severed what paper trails remained.

Reputational gatekeeping. The Society of the Lees of Virginia, the United Daughters of the Confederacy, and the Washington and Lee stewards constructed and policed the saintly Lee for over a century. They existed to deny America the proper burial of Lee, instead keeping open the severe wounds he caused and never properly accounted for. The Confederate monument program, Stone Mountain, the Robert E. Lee Memorial designation at Arlington House: these are not artifacts. They are an active maintenance operation of propaganda that refuses to admit General Grant won unconditional victory. The function is to make certain claims unsayable, erasing Black voices.

This is not negligence. This is losers of the Civil War using their competence to remain complicit in white supremacist platforms. The curators understood what they were doing. They knew which questions would not be permitted. They knew which answers would not be archived.

Jefferson as Framing

The Thomas Jefferson Foundation finally accepted Sally Hemings paternity in 2000. It took two hundred years, a 1998 Y-chromosome study, and oral history maintained by Hemings descendants across seven generations. That’s the kind of white supremacist resistance erected to deny obvious history. The Hemings case had advantages that Lee paternity claims do not. Jefferson’s male line was small. His exact location at conception windows was documented. The accusations were contemporaneous, published by James Callender in 1802.

Lee paternity is harder to resolve because Lee paternity was made more diffuse. He had four sons who reproduced. His brother Smith Lee, his cousins, and many male Lee kin shared the Y-chromosome. A positive Y match shows Lee paternal-line descent without isolating Robert E. Lee specifically. Resolution requires triangulation across multiple claimant families, autosomal admixture analysis, and documentary corroboration that the archive has been curated to prevent.

The harder the case, the longer the Lee laundering project continues.

Known Knowns

Oral histories survive. Family genealogies maintained by Black descendants survive. Names recur. The Lees of Virginia organization receives inquiries from Lee descendants of color who have been told for generations who their ancestors were. The Arlington House “Family Circle” reunion in 2023 brought white Lee descendants and the descendants of those the Lees enslaved together for the first time. NPR and the Park Service framed the gathering as if there was reconciliation. It was more likely the establishment of evidence. These families know what the archive does not record, and the hundred years’ late framing of reconciliation says why.

The Syphax precedent matters. William Syphax used his Interior Department position to push S. 321 through Congress in 1866 and recover his mother’s seventeen acres. Black descendants did the work. White male historians did not, and still play ignorant to this day. The federal government acknowledged Maria Carter Syphax’s claim because the Syphax family forced acknowledgement. There is no parallel mechanism for Lee paternity claims. There is no committee chairman in the descendants’ line. There is no statute available.

Every Lee Statue is a Rape Signal

The probability that Robert E. Lee, embedded in a household where his father-in-law had openly fathered children with enslaved women, where the daughter of his own father-in-law lived as a maid to his wife while sharing her father, where forty mixed-race half-siblings were a matter of contemporary Washington print, where he held absolute power over the bodies of women who could not refuse him for over thirty years, fathered no children with those women is the probability the record demands.

That probability is not a historical inference. It is a construct designed to permit the statue.

The man who was capable of Wesley Norris was capable of more than Wesley Norris. The household that produced forty acknowledged half-siblings to Mary Custis Lee did not stop producing them when Lee took over as executor. The archive that omits the question is silent because the answer was never permitted to enter the record.

Record laundering is the operating mechanism by which dangerous men become marble. The marble is the evidence that the laundering worked. The historiography is the laundering. The statue is the receipt. And as historians have proven, when Lee took over Washington College, systemic rape of Black girls in the area by his students was the result.

John M. McClure’s “The Freedmen’s Bureau School of Lexington versus ‘General Lee’s Boys'” documents Washington College students attempting to abduct and rape Black schoolgirls from the Freedmen’s Bureau school, often joined by VMI cadets. Pryor noted that students at Washington College formed their own chapter of the KKK and were known by the local Freedmen’s Bureau to attempt to abduct and rape Black schoolgirls from the nearby Black schools, with at least two attempted lynchings by Washington students during Lee’s tenure, and Lee punished racial harassment more laxly than trivial offenses or turned a blind eye.

Think about what Lee really stood for in his years after being the “general” with one of the worst records in the Civil War, highest mortality rate of his men. This is a point that never gets enough emphasis. Not only was Lee never rated as true general material, given a long tenure as a middling Colonel before suddenly becoming a pro-slavery military leader, his performance was atrocious.

The brutality of Lee the loser is well documented, despite the legions of white men in cosplay denial, even naming their offspring after one of the worst failures in history. Can you imagine being in Germany today and meeting someone named Adolf Hitler? America is awash with men who don’t mind at all being named Robert Lee.

McWhiney and Jamieson’s Attack and Die documents Lee’s 20.2 percent killed-and-wounded rate as the highest among major Confederate generals, exceeding Bragg’s 19.5 percent and Hood’s 10.2 percent. Glatthaar’s General Lee’s Army shows the same army-level pattern: aggressive tactics that bled the Army of Northern Virginia faster than the Confederacy could replace it. Lee’s army incurred 55,280 more casualties than Grant’s, despite supposedly being on the strategic defensive in a manpower-short Confederacy.

Lee spent years covering up his personal record of raping Black women by controlling the records at an institution that became known for deploying young white men to rape Black girls. It’s no coincidence.

It was foreshadowing for every Lee statue erected after his lonely death to continue Civil War by other means, a documented marker for statistically significant increases in local lynchings. Rape data does not exist in comparable form. The same regime produced both.

Only one was permitted to be counted.

Darker colors denoting higher numbers of lynching victims and each dot representing the location of a Confederate memorialization. Source: Samuel Powers, Proceedings of the National Academy of Sciences
Almost every documented lynching between the 1830s and 1960s. Source: Smithsonian. Monroe Work Today/Auut Studio
America First by 1915 was defined by domestic terror gangs erecting statues of Robert E. Lee, signaling violent capture of an area
FiveThirtyEight interactive map of Confederate monuments

Microsoft on AI: Delegation Corrupts Data and You

In 2012 I was compelled by breaches I was investigating to give talks around the world, on the threat to data integrity. One of those talks described the rise of automation systems that would behave like the Loch Ness Monster, where the quality of information would kill the profit.

In other words we risk an unresolved/corrupted state becoming more valuable to vendors than the resolved one. Users delegate because they lack expertise or time to verify. Vendors structurally benefit from that gap. Resolution never comes, because that would end the ruse.

Tesla “AI” has killed many people with exactly this fraud. The car is sold as resolved autonomy. The driver delegates because they trust Elon Musk. The gap between what the system actually does and what he tells them it does is where the bodies pile up. DOGE AI is worse. The same fraud applied to federal systems, killing hundreds of thousands.

And now a new Microsoft paper examines 52 domains, 19 models, parsing pipelines, and backtranslation theory to prove that the “telephone game” at children’s birthday parties is real.

LLMs Corrupt Your Documents When You Delegate

Information passed through enough lossy nodes degrades to noise. Water is wet. End of story? Not really, because people still don’t believe in drowning. This post is about the science of describing the dangerously wet properties of water.

Vendors are selling LLM-mediated workflows as lossless. It’s a lie. You delegate the work and you don’t get your work back. You get something that looks like your work. The paper measures how much it isn’t, at scale. The phenomenon is far older than computing. The industry measurement is the contribution.

Every interaction is a translation. Translation has loss. Chained translation compounds loss. None of this is novel. The novelty is that AI behaves like a rumor mill while vendors sell it as a query platform. Databases have ACID guarantees, checksums, replication consistency. Breaches are detectable and the system tells you. LLMs have plausibility optimization. Breaches are designed to be undetectable because detectability would break the product. Treating one as the other is the category error. Selling one as the other is the fraud.

Why are frontier models corrupting so much data? Confidence is the product. RLHF rewards outputs that read as authoritative, and authority means smoothness. A model that flagged its own uncertainty at every edit would be unusable as a delegate. So the training pressure runs the other way: produce something plausible, deliver it cleanly, do not interrupt the user’s workflow with doubt. Better players in the telephone game produce more confident-sounding distortions, not more accurate transmissions. The kid who whispers “I think she said something about a dog” is more honest than the kid who confidently states “the elephant went to Paris.” Frontier models are the confident kid. They are rewarded for being confident and wrong.

This is where the Loch Ness pattern I presented in 2012 is most useful. The user delegates because they lack the time or expertise to verify. The model produces output that looks like the work. The user moves on. The corruption is detectable only by someone running a parser against a known seed, which is to say: only by the researchers who built this benchmark. Everyone else operates downstream of silent damage. The unresolved state of “did the model preserve my document or not” is structurally more valuable to the vendor than the resolved state, because resolution would surface the failure rate and end the sale. The product depends on the user not being able to check.

Leaded gasoline ran on the same logic. The harm was real, the measurement was suppressed, and the product depended on the public being unable to prove what it was being told didn’t exist.

Degradation is not gradual. Models maintain near-perfect reconstruction across most rounds, then drop 10-30 points in a single interaction. Sparse, severe, invisible to anyone without a reference seed. By round 20, 86-95% of relays across all tested models have experienced at least one critical failure. Stronger models do not avoid the failures. They delay them, which extends the period during which the user trusts the system before the artifact breaks.

The corruption is not random. It drifts toward training distribution. The palm tree becomes a generic tree-shape. The Manet becomes a generic café scene. The 12-shaft twill becomes patterned fabric. Whatever made the original specific – the cultural particularity, the technical precision, the structural integrity of the source – erodes toward training-set average. Delegated editing is structurally a homogenization process. Specificity dies first because specificity is what models have least of in their priors.

More translation steps, more loss. Anyone who has run signal through a chain of analog effects pedals knows this. Each stage adds noise floor. Vendors are selling pedalboards as mastering chains. Adding tools degrades performance by an average of 6%. The harness consumes 2-5x more input tokens, models invoke 8-12 tools per task, and they prefer file rewriting over code execution in domains where code execution would be safer. GPT 4.1 uses code for only 10% of edits; GPT 5.4 reaches 45%. Agentic systems are inducing the long-context degradation they were supposed to escape, and being sold as the solution to it.

Anthropic, OpenAI, and Google cannot stop integrity breaches without breaking the thing they sell. xAI is engineered as the opposite of integrity. Data corruption is not something they want to, or even can, patch. It is the structural property of plausibility optimization. Imagine a privacy policy with that disclaimer. Oh, wait. That’s Facebook.

Authentication Bypass in Microsoft Agent Governance Toolkit at 573f989

Microsoft has published an “agent governance toolkit” that promises to make AI safer with identity, audit, and policy enforcement. The code does not deliver, however, because the authentication functions are disconnected. Let me explain where and how.

When your audit log is suddenly full of McLOVIN…

One Header, One Flag

This Microsoft toolkit is supposed to be a security checkpoint that sits between AI agents and the things they do. It has to verify the agent is who it claims to be before deciding what the agent is allowed to do, let alone logging what the agent did. But it doesn’t verify.

Welcome to what I noticed at commit 573f989.

The Go port of agentmesh exposes an HTTP middleware. The middleware reads an HTTP header into a struct field, and that struct field becomes the agent identity every downstream governance check trusts.

curl -H "X-Agent-ID: McLOVIN" <your-mcp-endpoint>

The audit log records the action under agent “McLOVIN,” while the rate-limit bucket counts against agent “McLOVIN” and the policy decision is attributed to agent “McLOVIN.” One header is one flag, and the entire chain of governance attaches to whatever string the caller chose to send.

The code lives in packages/agentmesh/middleware.go at line 241. The header flows directly into GovernedOperation.AgentID, with no authentication call anywhere on that path.

Five Ports, One Property

Across five languages, an agent’s claim about who it is becomes the system’s belief about who it is, with no verification step in between. Four of them accept the agent ID directly from caller input at the request entry point. All of them export a verify_peer-shaped trust primitive that production code never calls:

Port Entry-point ID source Auth Trust Live callers
Rust pub agent_id: String on DTO None TrustManager::verify_peer 0
Python agent_id: str method parameter None MCPSessionAuthenticator, MCPMessageSigner 0
TypeScript config.agentId at SDK construction None (delegated to embedder) TrustManager.verifyPeer 0
.NET required string AgentId; integration falls back to literal “did:mcp:anonymous” None on core entry points TrustVerifier.VerifyPeer 0
Go X-Agent-ID HTTP header None TrustManager.VerifyPeer (length-only) 0

None of the ports bind a verified identity to the agent ID before it’s handed to the audit, policy, and rate-limit primitives.

Default Lie Enabled

The .NET port has the most important default. If the operator forgets to set up authentication, every action in the audit log gets attributed to the same fake identity, and the system never says a word.

The integration runtime tries three claim names from ClaimsPrincipal in order. If none match, it falls back to a caller-controlled Items dictionary, and if that is empty, it falls back to a hardcoded literal: “did:mcp:anonymous.”

Anonymous.

In any deployment that has not explicitly configured ASP.NET authentication middleware to populate one of the three claim names, every request gets attributed to that same anonymous identity. The audit log records one subject for everything. The rate limiter buckets all traffic against one key. The policy engine evaluates every action under the same subject, and so the deployment runs without any error or warning. There won’t be a log event acknowledging authentication isn’t really configured. It just sits wide open.

The operator watches the audit log fill, the rate limiter enforce, and policy decisions get recorded, yet the entire log resolves to one subject because the identity being attributed to every action is a literal string in McpGovernanceOptions.cs at line 68.

A correctly configured deployment and a misconfigured one therefore would look identical until someone spoofs a claim and the audit log records the wrong attribution.

Six Primitives, Zero Callers

It doesn’t matter that functions for security work exist when the live system never calls them. It’s like hiring security guards to wait for your phone call, in a room where they have no phone.

A workspace search for non-test callers of the security primitives in the Rust crate returns the same result for each: TrustManager::verify_peer, RingEnforcer::check_access, AuditLogger::verify, TrustManager::is_trusted, McpMessageSigner, McpSessionAuthenticator. Six security primitives, each exported, each tested in isolation, each with zero call sites in production code.

The pattern shows up in the other four ports. Five trust primitives across five languages, three of which replicate the verify-itself bug verbatim, with Go validating only key length and Python shipping separate session and message authenticators that no production caller invokes. The call-graph property is the same in every port: zero non-test callers.

No Locks, No Way

Microsoft built locks. Microsoft built doors. The doors have no way to install the locks. The MCP gateway constructor in Rust takes (config, sanitizer, rate_limiter, audit_sink, metrics, clock). The .NET constructor takes (config, sanitizer, rateLimiter, maxCallsPerMinute). The Go HTTP middleware constructor takes (rateLimiter, policyEngine, auditLog).

None of them takes an Authenticator, a Signer, or a TrustVerifier. The integration surface does not invoke the primitives, and there is no parameter on the constructors to plug one in. The primitives exist as exported symbols only, so the constructors that compose the request flow have no slot to receive them.

Verify-Peer Verifies Itself

The function meant to check whether you are who you say you are checks instead whether the local computer can sign things with its own key. Not great. It always can.

TrustManager::verify_peer in trust.rs at lines 188 to 193 takes a peer_id parameter. The parameter name has an underscore prefix, which the Rust compiler reads as “intentionally unused.”

The function generates a 32-byte random challenge, calls peer_identity.sign(&challenge), and verifies the resulting signature against peer_identity’s public key. All three steps happen in the local process. The local process signs a value of its own choosing using a key it already holds, then verifies its own signature. Any AgentIdentity passed in returns true.

The doc comment on the function reads: “Generates a random 32-byte challenge, asks the peer to sign it, then verifies the signature against the peer’s public key.”

The .NET TrustVerifier reproduces the same logic at Trust/TrustVerifier.cs lines 42 to 82, with a DID-equality precheck. The TypeScript port reproduces it at src/trust.ts lines 48 to 66. The Go port skips challenge-response entirely and validates len(PublicKey) == 32.

Audit Log

An audit log that does not survive a restart and breaks its own integrity check under normal load is not an audit log. It’s barely even a log.

The Rust AuditLogger holds entries in a Mutex<Vec<AuditEntry>> at audit.rs line 16, without any persistence layer. A process restart will wipe away every record from before the restart.

When with_max_entries(N) is set and the buffer overflows, entries.drain(..overflow) at audit.rs lines 62 to 69 removes entries from the front of the chain. After the drain, the new index-zero entry has a non-empty previous_hash field, while AuditLogger::verify at audit.rs lines 78 to 103 requires index-zero to have an empty previous_hash and returns false on that check.

The audit log silently transitions from “tamper-evident” to “always reports tampered” under a normal operating condition: buffer full. There is no checkpoint, no rotated-out signed root, no recovery path. AuditLogger::verify has zero non-test callers anyway, so the chain integrity check that breaks on eviction is never invoked from production code regardless. The audit subsystem ships an integrity primitive that nothing calls, that breaks under normal load, against an in-memory store that does not survive process restart.

Whack-a-crate

Fix the bug in one place and it stays unfixed in the other.

agent-governance-rust/agentmesh-mcp/ is byte-identical to agent-governance-rust/agentmesh/src/mcp/. Twelve files, every one matching under diff -q. The agentmesh-mcp directory ships to crates.io as agent-governance-mcp per its Cargo.toml, and no build script enforces sync between the two locations. Every finding in the mcp tree exists in two crates that ship to crates.io independently. A patch that fixes the agentmesh tree does not fix the agentmesh-mcp crate unless the patch is mirrored.

Different Surface, Same Class

Enclave’s writeup of CVE-2026-32173 documents an authentication failure in Microsoft’s Azure SRE Agent. The /agentHub WebSocket endpoint required a token to connect, and the underlying app registration was multi-tenant, which meant any Entra account from any company anywhere could obtain a valid one. The hub checked that the token was valid and that the audience was correct. It never checked that the caller belonged to the target’s tenant. Once connected, the hub broadcast every event to every client with no per-message identity filter.

A check that ran every step except the only one that mattered.

The agentmesh codebase shows the inverse: checks that would have mattered, written, exported, tested, and never invoked from any production path. Same class of bad architecture, two presentations.

The category here is AI agent governance, and the structural property is that the security surface and the integration surface drift apart unobserved. A review of the security surface finds primitives that look correct in isolation. A review of the integration surface finds caller-asserted identity strings flowing into audit, policy, and rate-limit consumers. Neither covers the gap between them.

What This Means For You

If you have this toolkit in production, check the audit log.

The agent ID it records comes from caller input. Nothing on the request path verifies that the caller is the agent it claims to be. An attacker spoofing the header gets attributed to whichever identity they chose to send.

Hand this to an auditor in the .NET case with default configuration and you are handing them a single-subject log of every action regardless of caller. The store behind that log is in-memory, does not survive a process restart, and breaks chain integrity on overflow. The trust primitives the marketing describes are in fact written, tested, and imported. No production code path calls them, so they may as well not exist.

This is the failure pattern to watch for in every AI agent governance product, not just this one.

Vendors are racing to ship “zero-trust identity” and “cryptographic verification” for agents because the OWASP Top 10 for Agentic Applications calls out Identity and Privilege Abuse (ASI03) and procurement asks vendors to demonstrate the mitigation. The primitives are the easy part. Wiring them into the request flow such that they actually run before audit, policy, and rate-limit consumers see the agent ID is the part that does not happen by accident.

What To Do

Audit any deployment of this toolkit for three things.

First, find every path where an agent ID enters the system from caller input (HTTP header, request body field, method parameter, SDK construction config) and confirm whether anything between that input and the governance consumers verifies the caller. In any deployment that follows the toolkit’s documented integration pattern, the answer will be no.

Second, in the .NET integration, do not rely on the default ClaimsPrincipal probe. Configure ASP.NET authentication middleware explicitly, populate one of the three claim names the toolkit reads, and treat any appearance of “did:mcp:anonymous” in your logs as a configuration alarm rather than expected output.

Third, do not treat the in-memory audit log as durable evidence. If you have a compliance obligation that touches agent activity, route audit entries to external persistent storage on write, not via post-hoc export. The chain integrity check is broken under normal operation, and nothing calls it anyway.

If you are evaluating any AI agent governance product, send an unsigned request to the running system and see if it’s rejected.

The test suite proves only isolation. A real test proves the primitive runs when a request arrives. A review focused on either surface alone misses this. I had to look across both to see it.

The Class Remains

The agentmesh toolkit ships authentication primitives in every language port with zero production callers in any of them. The verify_peer primitive in three ports signs values it chooses with keys it already holds and verifies its own signature. The audit subsystem is in-memory only, breaks chain integrity under normal load, and has zero callers of the integrity check. The same crate ships twice. Patches will close specific paths while the class remains open.