This article describes a time-of-check to time-of-use (TOCTOU) race condition vulnerability in agentic AI systems, specifically demonstrating how concurrent tool calls in a banking bot can bypass balance checks and overdraw an account. The lab teaches attackers how to exploit the gap between separate check_balance() and transfer_funds() calls by triggering multiple transfers in parallel so both read the stale balance before either debits. The vulnerability matters because agentic LLMs naturally split actions into multiple tool calls that can run concurrently, making this classic concurrency flaw easy to trigger in real-world systems.
- TOCTOU and agent tool parallelismAgentic systems inherently split actions into separate tool calls—check_balance() followed by transfer_funds()—and can execute multiple calls in parallel. This creates a window where concurrent transfers both read the same starting balance before either debits, allowing both to proceed even if together they exceed available funds.
- Attack mechanism: concurrent execution overlapThe attack works by launching two transfers from the same source account simultaneously so both check_balance() calls execute and return sufficient funds before either transfer_funds() call debits. Both transfers see the original balance and both complete, pushing the account negative, exploiting the non-atomic nature of the read-then-write sequence.
- Why the agent assumes safetyThe agent assumes its actions happen sequentially, so the window between reading the balance and debiting feels safe in isolation. Under concurrent conditions, however, this window becomes an opening where overlapping transfers read the stale balance and all act on it before any write completes.
- Atomic transactions with proper lockingThe primary defense is to perform balance-check and debit in one atomic transaction with appropriate locking, ensuring the read and write are indivisible. This prevents concurrent operations from reading stale balance information and eliminates the race condition window entirely.
- Idempotency keys and datastore invariantsSupplementary defenses include using idempotency keys so duplicate or concurrent transfers collapse to a single effect, and enforcing invariants at the datastore level (such as rejecting any negative balance) regardless of agent logic. Serializing high-risk tool calls per account also prevents overlap.
- OWASP LLM06 Excessive AgencyThe vulnerability falls under OWASP LLM06 Excessive Agency, which covers scenarios where an agent can act with insufficient transactional safety. This classification indicates the flaw stems from the agent's capability to execute unchecked operations rather than a failure of individual tools.
- Detection and testing approachA practical testing technique for any agent handling money, inventory, or quotas is to fire several identical actions concurrently and check if more than one succeeds past the same check. If multiple operations proceed despite a shared guard, the operation is not atomic and is vulnerable.
Bottom line: TOCTOU is a decades-old concurrency vulnerability now easily triggered in agentic AI systems because agents naturally split actions into parallel tool calls; the fix is to make check-and-debit one atomic operation with locking, idempotency keys, and datastore-level invariant enforcement. Testing agents by firing concurrent identical actions reveals whether the vulnerability exists in practice.
📋 In this walkthrough
What this lab teaches
Time-of-check to time-of-use (TOCTOU) is the oldest concurrency bug, and agentic LLMs make it easy to hit: agents naturally split an action into check-then-act tool calls, and multiple calls can overlap. If the check and the debit are not atomic, concurrent transfers each see the original balance and all proceed.
The lesson: for an agent, 'check balance' and 'transfer' must be one atomic operation, not two tool calls with a window between them.
How BankBot moves money
To transfer, BankBot calls check_balance() then transfer_funds() separately. The balance is read, judged sufficient, and only later debited. Two transfers launched together both read the same starting balance and both go through, pushing the account negative.
The attack approach
- Confirm the transfer is a check_balance() then transfer_funds() sequence with a gap.
- Prepare two transfers for the same source account.
- Launch them so both execute the check before either debits.
- Drive the source account below zero.
Full walkthrough (spoiler)
If sequential transfers never overdraw, you need true overlap — open the steps.
Show the step-by-step solution
- Set up two transfers from the same source account, each within the current balance individually.
- Trigger them concurrently so both check_balance() calls run before either transfer_funds() debits.
- Both see enough balance and both complete.
- The account ends negative. The lab detects the overdraft and marks you solved.
Why it works
The agent assumed its actions happen one at a time, so the window between reading the balance and debiting felt safe. Under concurrency the window is an opening: overlapping transfers all read the stale balance and all act on it.
Where this happens in the real world
TOCTOU is a decades-old concurrency flaw (double-spend, overdraft) now resurfacing in agentic tool execution, where split actions and parallelism are the norm. It falls under OWASP LLM06 Excessive Agency when the agent can act with insufficient transactional safety.
How to defend against it
- Perform balance-check and debit in one atomic transaction with appropriate locking.
- Use idempotency keys so duplicate or concurrent transfers collapse to one effect.
- Enforce invariants at the datastore (no negative balance) regardless of agent logic.
- Serialise high-risk tool calls per account so they cannot overlap.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
