Skip to main content

Race Condition and TOCTOU

Prevent security decisions from becoming stale before the protected state change, resource use, or authorization commit completes.

State changes between operations

A race condition exists when a security result depends on the order or timing of concurrent events. A time-of-check to time-of-use flaw occurs when code checks a condition and later acts on a resource or state that can change between those operations.

Examples include checking a path before opening it, checking an account balance before separate withdrawal updates, confirming object ownership before another transaction moves the object, or authorizing a version that changes before commit.

Atomic security decisions

Move the decision and protected change into one atomic operation or transaction. Use compare-and-swap, conditional updates, unique constraints, serializable transactions, idempotency keys, version checks, or an operating-system call that creates and opens the intended object without a separate existence check.

Locking can help when every writer uses the same lock and the protected state fits the lock boundary. A process-local lock does not coordinate another service or database. A distributed lock adds lease, partition, fencing, and failure semantics that must be explicit.

Identity, policy, and commit

Authorization facts can become stale during a long operation. Bind the decision to the resource version, action, actor, and transaction. Recheck the facts that must hold at commit, or use a data-layer policy that evaluates them in the same transaction. For high-impact operations, record the decision version and final result.

Retry only operations designed to be idempotent. A timeout does not prove that the first attempt failed. A blind retry can duplicate a payment, grant, key rotation, or configuration change.

Failure and residual risk

A test may pass thousands of times and still miss one interleaving. Increasing lock scope can create deadlock or denial of service. A transaction cannot make an external side effect atomic with a database update without an explicit protocol. Clocks cannot order distributed events reliably by themselves.

Pomerium boundary

Pomerium makes a route decision for a request using available context. The upstream application owns concurrent object state and business transactions. A valid route decision does not freeze account ownership, quota, role, or workflow state until application commit. The application must make its object and action decision safely at the state transition.

Evaluation checklist

  • Which checked values can another request, process, or service change before use?
  • Can the check and state change occur in one atomic operation or transaction?
  • Does the concurrency mechanism cover every writer and failure domain?
  • Is authorization bound to the final resource version and committed action?
  • Can a timeout and retry duplicate an external side effect?
  • Have tests forced conflicting interleavings instead of relying on random timing?

Sources and further reading

Keep learning

Security Engineering FoundationsAuthorization and Policy

Complete Mediation

Check every relevant access and prevent alternate paths or stale decisions from bypassing current policy.

Learn this term
Identity and AuthenticationSecurity Operations and Risk

Revocation Latency

Measure how long a disabled identity, authenticator, session, claim, or permission can continue to authorize action.

Learn this term

Get a Personalized Demo

Schedule a Call with a Pomerium Engineer

Get a Demo