1
4 Comments

The $5 to $500,000 attack we didn't know we had

We posted about TrustLoop on the n8n community forum recently. TrustLoop is an AI agent governance platform — it intercepts tool calls, logs them, and enforces rules before actions execute. We thought we had built something solid.

A commenter disagreed. He left a long, detailed technical reply pointing out that our human approval workflow had a fundamental flaw. The short version: someone could approve a $5 transaction and an agent could execute a $500,000 one.

Here is how it works.

When TrustLoop decides a tool call needs human approval, it pauses the agent and sends an email to the approver. The approver sees the tool name and arguments — "transfer funds, amount: $5, recipient: acme@example.com" — and clicks Approve. The agent retries. TrustLoop sees the approval and allows the action to execute.

The problem is what we were not checking. When the agent retried, we verified that a valid approval existed. We did not verify that the arguments being submitted on the retry were the same arguments the human had approved. A misconfigured or malicious agent could surface a small innocuous action for approval and then execute a completely different one. The approval was real. The authorisation was not.

This is not a hypothetical. It is a real vulnerability in any approval system that does not hash the approved payload.

I had thought about this problem in the abstract. I had not built the fix. The commenter had correctly identified that we had an AI governance tool with a governance hole in it.

We did not get defensive. He was right. We replied, acknowledged it, and went back to work.

Forty-eight hours later we had shipped three things.

The first was payload hash verification. When TrustLoop intercepts a tool call and escalates it for approval, it now computes a SHA-256 hash of the exact arguments at that moment and stores it against the approval record. The hash is returned to the agent in the pending response. When the agent retries after approval, it must pass back both the approval ID and the hash. TrustLoop verifies that the approval is genuine, that the hash matches the stored one, and that the arguments being submitted right now hash to the same value. All three must match. If anything has changed, the action is blocked. The hole is closed.

The second was encrypted credential storage. The commenter also pointed out that in our forwarding model — where TrustLoop forwards approved actions to downstream services — agents were expected to hold the API keys for those services themselves. That is a bad pattern. Every agent deployment ends up holding sensitive credentials it has no business holding. We built a credential vault: customers store their tool API keys in TrustLoop, encrypted with AES-256-GCM. When a forwarded call executes, TrustLoop decrypts the credential and injects it as a header. The agent never touches it.

The third was a Tool Registry dashboard so customers can register tools, store credentials, and manage everything without touching the API directly.

None of this was on the roadmap for that week. All of it should have been built earlier.

The thing I keep thinking about is how close I came to skimming past that comment. It was long, technical, and arrived on a post I was half-expecting to go unread. The instinct when someone critiques your product publicly is to respond briefly and move on. Reading it properly was the better decision by a wide margin.

The product is more secure because a stranger on the internet took the time to explain what we had missed.

If someone leaves you a detailed critical comment, read it twice before you respond. They might be wrong. But they might have found something you have been too close to see.

on July 15, 2026
  1. 1

    Does the approval get marked consumed after its first successful verify? That was my question at the hash section: binding the payload stops argument swaps, but a second retry with identical arguments still hashes clean. Might already be handled and just didn't make the writeup.

    1. 1

      You are right and that's a real gap, good catch.

      Binding the payload hash stops someone swapping arguments, but it doesn't stop the same approval being replayed a second time with identical arguments. The hash clears both times because nothing changed.

      Just shipped the fix. The approval now gets marked consumed the moment it's first used. Any retry after that, even with a perfect hash match, gets blocked. One approval, one execution.

      Appreciate you pushing on it. That's exactly the kind of thing that's easy to miss when you are building it.

      1. 1

        Anytime, these approval flows are fun to poke at. Replay gaps hide well because the valid path and the replay look identical to the code, so nothing feels off until the same request lands twice. Consuming the approval on first use shuts it at the source, and turning that around in a day is quick.

  2. 1

    If you found this useful, we share more of this kind of thinking on X and LinkedIn. The full product is at trustloop.live . Links below — would love to connect.

    X: https://x.com/sojimathewj , https://x.com/Trustloop_HQ
    Linkedin: https://www.linkedin.com/company/trustloophq/