TL;DR
A reproduced vulnerability class, documented in tested setups across three released agent products, shows that a human can approve one operation while the system executes a different one—same approver, same click. The paper calls it Loopjacking. The failure isn't who clicked approve. It's that nothing checked whether the thing that ran was still the thing that was shown.
What the paper found
A new paper, "Loopjacking: Hijacking Human-in-the-Loop Approval" (Kumar, arXiv:2609.21081, September 2026), reproduces a vulnerability class in tested setups across three released agent products: a human approves one operation, and the system executes a different one in those setups—same approver, same click. Approval alone has already come up short as a control in other incidents; Loopjacking is a specific, reproducible mechanism for exactly that gap. The paper's own framing: "Human approval is often treated as the last security boundary before an agent executes a consequential operation. That boundary is only meaningful if the operation presented for review is the operation later authorized or released."
Two ways approved A becomes executed B
The paper defines two attack shapes, both landing on the same outcome—approved A, executed B.
Representation-based Loopjacking: "The complete request or execution context contains B before the decision, but the product displays, canonicalizes, or checks a materially incomplete A." The dangerous operation is already sitting in the request; the review surface just doesn't show all of it.
Post-approval state-substitution: "The human sees and approves exact A. Before the approval is consumed, an actor changes pending task, thread, session, or continuation state to B." The reviewer sees the real thing—then it gets swapped before the approval is consumed.
What the paper reproduced
This isn't a theoretical construction. The author reproduced both attack shapes against named, versioned products:
| Product | Attack shape | Versions tested | Fix status |
|---|---|---|---|
| Agno AgentOS | Post-approval state-substitution | Seven releases through 3.0.9 | No fixed release known as of the paper's cutoff |
| LangGraph Agent Server | Post-approval state-substitution | Twelve versions, 0.7.5 through 0.14.0 | Reproduced only in a specific in-memory composition whose authorization policy let a non-approver edit a pending thread; a supported deny policy blocked it. No claim about default or Postgres-backed production deployments. |
| OpenClaw | Representation-mismatch | v2026.2.23 | Fixed in 2026.2.24 |
OpenClaw's mismatch was already a disclosed vulnerability (CVE-2026-32052, fixed in 2026.2.24). The Agno and LangGraph results carry no CVE, and the author's own evidence archive still lists no vendor-fixed release for either as of the paper's evidence cutoff (2026-09-10).
One system rejected the substitution: the OpenAI Agents SDK (v0.22.0, v0.22.2). The paper tested it only against post-approval state-substitution—when the serialized pending call was changed after approval, resume failed and nothing ran, because ordinary per-call approval keeps a canonical record of the exact invocation. That's a design choice, not an unavoidable property of agent orchestration. The paper is explicit that it's a negative control, not a claim that all application-authored approval around the SDK is safe: it doesn't cover a sticky always-approve policy or an attacker able to forge every trusted canonical field. It also wasn't tested against the representation-based variant at all.
The paper is upfront about its own scope: one researcher, a purposive rather than random sample of products, no independent reproduction, and no CVSS or severity score of its own attached to any finding (OpenClaw's advisory rates its case medium). That narrows what the results say about how common this is across the ecosystem—the paper itself says its results don't estimate ecosystem prevalence. It doesn't narrow whether the mechanism is real—the reproduction is direct, against real code, with real version numbers.
Twenty units approved, two thousand executed
The paper's own illustration: an administrator reviews a transfer of 20 units to an approved vendor. Before the approval is consumed, the pending arguments are replaced with a transfer of 2,000 units to an attacker-controlled destination, a hundred times the amount.
The shape is the one that matters for anyone signing off on agent actions: the approver saw a small, plausible request and authorized it. What executed was a different request entirely, and the approval that authorized it was never re-checked against what ran.
Why this isn't the same gap as channel separation
A related but distinct failure mode is worth naming so the two don't get conflated. Channel separation—keeping an agent's own execution channel, such as its CLI or an API token, out of the set of channels allowed to approve—closes a who/where gap: an agent can't rubber-stamp its own request over the channel it used to make it.
Loopjacking is a what gap. Even with channel separation working exactly as designed—a genuine human, on a genuine approval channel, reviewing a genuine request—the operation that gets consumed can still be a different one than what that human looked at. Channel separation answers "did this approval arrive over a channel the requester couldn't use to approve itself." It doesn't answer "is the thing that ran still the thing that was shown." Those are different questions, and each needs its own check.
What actually closes it
The paper's proposed mitigations aren't exotic: canonical approval records that bind the complete action identity—arguments, target resource, principal, scope—into a single complete canonical descriptor; a comparison at use time, at the last authorization point, not just at review time, that reconstructs the operation about to execute and checks it against that descriptor; or authorization policies that stop any untrusted actor from modifying pending approved state.
In the tested Agno releases and the tested LangGraph composition, nothing compared the operation at use time with what was approved. OpenClaw 2026.2.24 added a check against the full shell argument vector; a later OpenClaw advisory (GHSA-2j8v-hwgc-x698) lists a related shell-wrapper fix in 2026.5.18, so a deployment on an intervening version isn't covered by the earlier fix alone. The comparison the OpenAI Agents SDK's negative-control result relies on is, per the paper's own account, what the other two cases lack.
The question worth asking
If your team runs agents with human-in-the-loop approval on anything consequential—a transfer, a deletion, a privileged command—the paper's contribution is a specific question to bring to whatever's gating that approval: does the system check, at the moment of execution, that the operation matches what was reviewed? Or does it only check that someone with permission to approve clicked approve?
Those are different guarantees. Loopjacking happens when a system builds the second one and assumes it covers the first.
AI agent governance needs both questions to be answered.
