What it takes to get an AI agent's command safely onto a real machine — and what happens when nobody authorises it
An independent test report published in April concluded that the transport carrying today's AI-agent traffic could be replaced without touching the protocols above it — “keep the protocols, change the plumbing.” We tested that on a working system that operates real equipment. It holds. This is what it cost, and the four things worth acting on.
We run an AI agent that can operate physical equipment through a set of controlled tools. Until 14 August it reached those tools the ordinary way: over the public internet, through an address anyone can find by scanning. We replaced that path with atSign's transport, where neither end opens a port and the network carrying the traffic cannot read it.
Then we re-ran the safety test that decides whether the agent may move a machine — same test, same credential, recorded four days earlier over the old path.
Nothing above or below the change noticed. The reply came back identical to the byte, and the safety test gave the same answer word for word.
Every figure here came from a scripted run that can be re-executed on request — including by you, on your own hardware, before you believe any of it.
Two signatures, two different jobs — and this is the distinction most often collapsed. The diagram shows both, because neither can do the other's work.
| proves | lives | scope | |
|---|---|---|---|
| WebAuthn key or phone |
a human was physically here, for this action, now | on the authenticator | bound to one origin; anonymous by design; deliberately not a general signing oracle |
| atSign | who — checkable against a published public key | the .atKeys file, held by the local signer |
durable, publishable, independent of the browser session that produced it |
⚠ atSign is not a token-issuing authorisation server, and reading it as one is the most common mistake made about this architecture. There is no central grant and no “approve command” verdict anywhere in the chain: verification happens at the receiver, against a public key the sender published. The signing plane is never the actuation path.
Both branches were exercised, and the refusal branch is the one that matters. With no tap there is no grant, no signed envelope and nothing for the cell to verify — so the machine stays still. That is not an absence of evidence. It is the outcome the whole construction exists to produce, and it is the branch an attacker has to beat. A deny-by-default system is proven by what it declines to do.
The stack on the other side of that decision drives real hardware today. The same tool surface walks an untethered quadruped over Bluetooth and reads live sensor data back on the same link — no tether, no third-party runtime in the path. The August run stopped at the equipment boundary because that is where the measurement stopped being about the transport. Three weeks later we closed that gap, and it is the next section.
The chain above, driven end to end: a human authorised one action, the payload was signed, and the quadruped moved — under a single sealed record. Then we withheld the authorisation and it did not.
The August run measured the transport and the decision. This one joined them to the equipment. One run identifier covers the authorisation, the signature and four actuated steps; the seal's hash is the head of the event chain it closes over, and the chain verifies. We then ran the same mission again and did not authorise it. No grant was issued, no envelope was signed, the cell had nothing to verify, and the machine stayed still — sealed and verified like any other run.
First, what changed and what did not: the phone replaced the security key, not the identity that signs. Both runs were signed by the same atSign. Presence and provenance are separate jobs, as the table above sets out, and only the presence half had a choice of device.
We intended to run this with a hardware key. On the day it would not enumerate — the fault was a charge-only adapter, which produces no error anywhere — so the first run was authorised by a phone instead. We then found the adapter and ran it again, unchanged, with the key. Two runs differing in one variable is a better result than the one we set out to get.
The hardware key carried a real signature counter, so a replayed assertion can be detected — but it proved only that someone touched it. The phone carried a verified biometric and no counter at all, and a phone passkey may be synced across a vendor's account, so it is not bound to one device the way a key is. Each is stronger where the other is weaker.
So the authenticator is a policy question, not a hardware one. What a deployment should decide is which class of device a given class of action requires — routine supervision and a high-consequence actuation are not the same ask. Every authorisation record carries what answered and how, so such a rule has something to rest on. ⚠ We have not built that rule, and we are not claiming it.
Choosing between them. The action decides the authenticator; where the work happens is a constraint on top, not the reason. ⚠ This is how we would advise choosing — it is reasoning from the two runs above, not a measurement, and it is not something the software enforces today.
Need to detect a replayed assertion, or prove the credential never left one device? → a security key. It is the only one of the two that carries a counter, and the only one that cannot be copied to a second device.
Need to prove which person, not merely that someone was present? → a phone, whose biometric verified the holder. A key can do this too, but only if user verification is required of it — which means its PIN, and that is a real trade rather than a setting to flip without thinking.
A phone cannot enter the area? → a key. In a cleanroom, an explosive atmosphere or a secure site this is not a preference, and no amount of architecture argues with the door.
A shared workstation with many operators? → a key each. A credential bound to the machine cannot tell you which of them was standing there.
Field or remote work with no fixed console? → a phone. It is the device that is already going to be there.
No human at the machine at all? → neither. That position wants a public key, not an authenticator: it verifies a signature before it acts, and the human who authorised the action was somewhere else, earlier. A security key installed at an unattended controller does not create presence — it relocates the appearance of it, which is the failure this whole construction exists to prevent.
The records are still “authenticated sender.” Nothing here produced a detached signature an outsider could check offline from public information, so the wording does not move. The second of the two questions below we still do not pass, and we said so before we ran.
Confirmation is still not independent. The robot acknowledged each command and we recorded the acknowledgement. That is commanded and acknowledged, which is not the same as verified — real confirmation of a physical outcome comes from an observer that is not the robot.
One public address is still there. We know exactly what closes it: a documented way to trust the encryption on a private link between the sandbox and a service on its own host. A shortcut was available and we turned it down, because taking it would have cost the ability to inspect what the agent is asking for. That was the wrong trade, and it still is.
And it is still one agent at a time. Population remains the number we do not have, and it is the one a buyer with a floor full of them will ask for first.
The construction is not specific to the hardware we built it on. It asks three things of a controller: that it can hold a public key, that it can verify a signature before it acts, and that it can refuse. Nothing else in it is ours — not the vendor, not the fieldbus, not the protocol above it. We built and measured on the controller that is on our bench.
We state that as scope, not as a hope. The alternative has no end: an answer for one controller invites “but not that one”, and that objection can be made indefinitely by anyone who would rather not decide. A construction either generalises or it does not. This one does, because the property it rests on — the ability to check a signature before acting — is not a point of difference between controllers.
The US authorities made exactly this move five days after we ran the test, and it is worth noting who made it. Having named specific Siemens S7 models as the subject of an active threat, the National Security Agency, CISA, the FBI, the Department of Energy and the Environmental Protection Agency wrote that “ongoing PLC targeting activity is broader than Siemens PLCs” and that “all PLC owners and operators should apply relevant mitigations.” The threat is not model-specific, and they said so while naming models. Neither is the answer.
What that advisory describes is the reason this paper exists. Attackers are using AI-generated scripts that mimic legitimate monitoring tools — which means the defence cannot be recognising a bad client. Every detection method the advisory recommends is an inference about whether a human authorised an action: writes outside change windows, activity out of hours, “patterns consistent with automated scripting rather than human operators”, changes with no matching work order. Against a tool built to look legitimate, each of those is a guess. A command that carries an identity, or does not run, is not a guess.
Two questions separate security that can be demonstrated from security that is merely asserted. We apply both to ourselves here, and we do not yet pass all of the second.
The platform underneath us can silently reject an unauthorised request, or it can let the application see it and record a refusal — but not both at once. We chose the recordable option, because a refusal nobody can evidence is worth little to an auditor, and closed the resulting gap another way. Ask any vendor which of the two they do. A system that drops bad requests quietly cannot tell you afterwards what it stopped, and cannot let the caller tell refusal apart from an outage. That is the difference between “secure” and “demonstrably secure”, and the second is the one a regulated buyer is paying for.
Our messages are encrypted and authenticated between the two parties, so the receiver knows who sent what. That is not the same as a signature an independent third party can check afterwards from public information, without trusting either side. Wherever someone outside has to adjudicate — an audit, a dispute, an insurance claim, a regulator asking what happened — that distinction is the difference between evidence and assertion. So we describe our records as “authenticated sender” and will not claim more until it is true. It is solvable and we are solving it. Anyone who cannot tell you which of the two they have should be assumed to have the weaker one.
Partly up to you. Each gap named above has a known answer, and none of them is free. Which is worth closing first depends on where you sit — a regulated operator, a systems integrator and a robot vendor would not rank them the same way, and we would rather be told than guess.
If you have run into any of this, or you think we have the priorities wrong, say so: linkedin.com/company/digital2win. Every figure in this note came from a scripted run that can be re-executed on request — including by you, on your own hardware.