Join our Newsletter — 33% off our NHI Course
Home› Guides› Race Condition Vulnerabilities Guide: Concurrency Flaws and Safe…
Guide Application Security

Race Condition Vulnerabilities Guide: Concurrency Flaws and Safe Design

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 12 min read
On this page

A race condition turns a correct check into a wrong decision because something changed between the moment the code checked and the moment it acted. In web applications that means a voucher redeemed twice, a balance overdrawn or a limit exceeded when several requests arrive together; in operating systems and CI/CD it means a file swapped or a token used inside a short window. This guide explains the weakness family (CWE-362 and its children, including TOCTOU), where it appears, how to detect it and how to design it out with atomic operations, locking, isolation levels and idempotency. It is for developers, architects and application security teams; it is defensive and gives no exploitation procedure. For where these weaknesses rank among the most dangerous software flaws generally, see the CWE Top 25 Guide; this page goes deeper on concurrency design only.

Key takeaways

  • Check and act must be one step. OWASP ASVS 5.0 V15.4.2 requires that checks on a resource's state and the actions that depend on them run as a single atomic operation to prevent TOCTOU.
  • Read-then-write in application code is the usual bug. Reading a balance, deciding in code and then writing back leaves a window; a conditional update or a row lock closes it.
  • Know your database default. PostgreSQL defaults to Read Committed, which permits nonrepeatable reads and serialisation anomalies; Serializable prevents them but requires retrying transactions that fail with SQLSTATE 40001.
  • Constraints beat code. A unique constraint on a redemption record holds no matter how many requests race, and is the cheapest durable fix for single-use actions.
  • Short windows are still windows. Unit 42's ArtiPACKED research showed a token valid only until a CI job ended could still be used within that time; shrinking a window reduces risk but does not remove it.

How the attack works

MITRE defines CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') as a code sequence that needs temporary exclusive access to a shared resource, with a timing window in which another concurrent sequence can modify it. MITRE describes two properties the sequence should have: exclusivity (no other sequence can change the resource until it finishes) and atomicity (the sequence behaves as one indivisible unit). A race condition is the loss of either.

CWE-367 Time-of-check Time-of-use (TOCTOU) is the most common form: the product checks a resource's state before using it, and the state changes between check and use, invalidating the check. In a web application the "resource" is usually a database row (a balance, a stock count, a coupon's used flag); in an operating system it is often a file path or permission.

CWENameTypical setting
CWE-362Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')Parent class for all of the below
CWE-367Time-of-check Time-of-use (TOCTOU) Race ConditionWeb limit checks, file access checks
CWE-364Signal Handler Race ConditionNative code handling asynchronous signals
CWE-366Race Condition within a ThreadShared in-memory state in multi-threaded services
CWE-368Context Switching Race ConditionOperations that switch privilege or security context
CWE-421Race Condition During Access to Alternate ChannelSide channels opened for a privileged operation
CWE-689Permission Race Condition During Resource CopyFiles copied before permissions are applied
CWE-1223Race Condition for Write-Once AttributesHardware and firmware registers

MITRE CAPEC describes the attacker view as CAPEC-26 Leveraging Race Conditions and CAPEC-29 Leveraging Time-of-Check and Time-of-Use (TOCTOU) Race Conditions. Defenders can use those entries to frame threat models; this guide stays on the design side.

Where it shows up

  • Limits and single-use actions: coupon and gift card redemption, referral bonuses, one-vote-per-user, free-trial activation, withdrawal limits. The code checks "not yet used" or "within limit" and then records the use in a separate statement.
  • Checkout and inventory: the last item in stock sold to two buyers, or a seat booked twice. ASVS V2.3.4 asks for business-level locking so limited quantity resources such as theatre seats or delivery slots cannot be double booked.
  • Balances and ledgers: transfers that read a balance, subtract in application code and write the result, allowing concurrent transfers to overdraw.
  • Authentication and session state: one-time codes or recovery tokens accepted twice if the "consumed" flag is set after validation; session upgrade and logout racing each other.
  • Files and temporary resources: a program checks permissions on a path and then opens it, letting the path be replaced in between (the classic CWE-367 case in native code).
  • Multi-threaded services: caches and shared objects mutated without synchronisation. ASVS V15.4.1 requires thread-safe types and locks or semaphores for shared objects.
  • CI/CD and short-lived credentials: tokens valid only while a job runs can still be used if they leak during the run. See the GitHub and GitHub Actions Security Guide.
  • Distributed systems: two service instances, or a retry and its original, both processing the same message because deduplication happens after the side effect.

Impact

ImpactExampleSeverity driver
Limit bypass and financial lossA single-use credit applied several timesValue per action and how easily concurrency is achieved
Data integrityLost updates, negative stock, ledger out of balanceWhether reconciliation detects it
Privilege escalationFile replaced between permission check and use by a privileged processPrivilege of the vulnerable process (CWE-362 mitigations include running with least privilege)
Credential misuseA leaked token used before it expiresToken scope and lifetime
AvailabilityDeadlocks or thread starvation from poor locking (ASVS V15.4.3, V15.4.4)Lock scope and retry behaviour

Detection

Before release

  • Code review patterns: flag any "select, decide in code, then update" sequence on shared state, any check-then-open on file paths, and any shared mutable object without synchronisation. See the Secure Code Review Guide.
  • Concurrency tests: for every single-use or limited action, add an automated test that fires many identical requests in parallel against a test environment and asserts the invariant still holds (one redemption, no negative balance). This is a functional test of your own system, not an attack tool.
  • Static and dynamic tooling: thread sanitisers and static analysers find some in-process data races; MITRE notes static analysis can find some instances, but business-level races across requests generally need targeted tests.
  • Penetration testing: include concurrency in scope for transactional flows. See the Web Application Security Testing Guide.

In production

  • Invariant monitors: alert on negative balances or stock, a voucher with more than one redemption, or more orders than inventory.
  • Burst detection: identical requests from one session or key arriving within milliseconds on sensitive endpoints.
  • Database signals: rates of serialisation failures (SQLSTATE 40001), deadlocks and lock waits; a sudden rise may reveal contention on a flow you did not know was shared.
  • Idempotency conflicts: count 409 responses for in-flight duplicate keys; spikes indicate aggressive retries or abuse.

Metrics:

  1. Share of single-use and limited endpoints protected by a constraint, conditional update or lock (target 100%).
  2. Share of those endpoints with a parallel-request test in CI.
  3. Invariant violations detected by reconciliation per month, trending to zero.
  4. Serialisation failure and deadlock rates, with retries succeeding within the configured limit.
  5. Race findings per penetration test or bug bounty period.

Prevention and hardening

Design patterns

PatternHow it closes the windowUse whenTrade-off
Database constraint (unique, check)The second conflicting write fails at commitSingle-use claims, one record per key, non-negative valuesMust handle the violation error cleanly
Conditional atomic updateCheck and change in one statement, for example update only where balance is sufficient, then confirm one row changedCounters, balances, stock decrementsLogic must fit in one statement
Pessimistic row lock (SELECT ... FOR UPDATE)Other writers block until the transaction endsMulti-step logic on a few hot rowsContention and deadlock risk; keep transactions short
Optimistic concurrency (version column)Write succeeds only if the version is unchangedLow contention, user editsCaller must retry on conflict
Serializable isolationDatabase aborts transactions that could not have run seriallyComplex invariants across many rowsMust retry whole transaction on 40001; more aborts under load
Idempotency keyDuplicate requests return the stored result instead of re-executingPayments, order creation, any retried POSTKey store must itself be atomic
Single-writer queue or partitionAll changes to one entity are processed seriallyHigh-throughput ledgers, event-driven systemsArchitecture change; added latency

Database specifics

  • Isolation level: PostgreSQL's default Read Committed takes a new snapshot per statement, so two reads in one transaction can differ. Repeatable Read fixes the snapshot but can still allow serialisation anomalies. Serializable guarantees committed transactions have the same effect as running one at a time, using non-blocking predicate locks.
  • Retry correctly: PostgreSQL advises that applications at Repeatable Read or Serializable must retry on serialisation failure, rerunning the whole transaction rather than the failed statement, with a limit and backoff.
  • Row locks: FOR UPDATE blocks other UPDATE, DELETE and SELECT FOR ... on the same rows until the transaction ends; FOR SHARE allows other readers that lock in share mode but blocks writers.
  • Advisory locks: application-defined locks that the server does not enforce; prefer transaction-level advisory locks, which release automatically at transaction end, over session-level ones, which survive rollback.
  • Deadlocks: PostgreSQL detects and aborts one transaction; prevent them by acquiring locks on multiple objects in a consistent order and avoid holding transactions open while waiting for user input. See the Database Security Guide.

Code and platform

  • Lock before checking: MITRE's CWE-367 mitigations include acquiring the lock before the check so the resource checked is the resource used, and rechecking after use.
  • Use atomic primitives: CWE-362 notes that statements such as x++ are not atomic at the instruction level; use atomic types, mutexes around only the critical section, and thread-safe libraries.
  • Files: operate on file handles rather than repeatedly on paths, create temporary files with exclusive-create semantics, and run with the least privilege needed.
  • Consume before acting: mark one-time tokens as used in the same atomic step that validates them.
  • Distributed locks with care: a lock in a cache cluster can expire while work continues; pair it with a fencing check (a version or constraint) at the database.
  • Short-lived credentials: scope CI tokens to the minimum permissions and keep secrets out of build artefacts, so a leak inside the validity window has little value. See the CI/CD Security Guide.

Rollout

  1. Find shared state: list endpoints that change balances, counters, stock, single-use items or tokens.
  2. Write invariants: state each rule in a testable form ("a voucher has at most one redemption").
  3. Add tests first: write parallel-request tests that currently fail where a race exists; they prove the fix later.
  4. Fix with the lightest durable control: constraint, then conditional update, then lock or isolation change. Deploy behind a feature flag and pilot.
  5. Watch contention: monitor lock waits, deadlocks and 40001 rates during the pilot; the flag is the rollback.
  6. Add reconciliation: scheduled invariant checks catch anything the design missed. Fold the patterns into the Secure Software Development Lifecycle (SSDLC) Guide standards so new services start safe.

Decision guidance

  • Small team, single database: rely on unique and check constraints plus conditional updates; they need no new infrastructure.
  • Complex invariants across tables: use Serializable for those transactions only, with a tested retry wrapper.
  • Hot rows under heavy load: prefer conditional updates or a single-writer queue over long pessimistic locks.
  • Public APIs with retries: require idempotency keys; the IETF Idempotency-Key header draft (work in progress) suggests 409 Conflict while the original request is in progress and 422 when a key is reused with a different payload. See the API Security Guide.

Framework mapping

FrameworkReferenceRelevance
OWASP ASVS 5.0V15.4.1 to V15.4.4 Safe Concurrency; V2.3.3; V2.3.4Thread safety, atomic check-and-act, consistent locking, fairness, transactions, business locking
MITRE CWECWE-362, CWE-367, CWE-364, CWE-366, CWE-368Root cause mapping
MITRE CAPECCAPEC-26, CAPEC-29Attack patterns for threat models
NIST SP 800-53 Rev. 5SA-8, SA-11, SC-24, SI-4Engineering principles, developer testing, fail in known state, monitoring
NIST CSF 2.0PR.PS-06, ID.RA-01, DE.CM-09Secure development, vulnerability identification, monitoring

Lessons from incidents

  • A short validity window was enough: in ArtiPACKED 2024, Unit 42 found GITHUB_TOKEN values persisted in public build artefacts. The token expired when the job finished, but artefacts could be downloaded while the workflow was still running, so where steps followed the upload there was a window to use it. The lesson: expiry is not a substitute for keeping the secret out of the artefact.
  • Checks in code, writes elsewhere: validating a limit in the application and recording the use in a later statement is the single most common web race pattern.
  • Raising isolation without retries: switching to Serializable and then surfacing 40001 errors to users or dropping the transaction trades a security bug for an availability bug.
  • Distributed locks without fencing: a cache lock that expires mid-operation lets a second worker proceed; the database must still reject the conflicting write.
  • Testing serially: functional suites send one request at a time and never see the race.

Practitioner checklist

  • Inventory endpoints that change balances, counters, stock, single-use items or tokens.
  • Express each invariant as a database constraint wherever possible.
  • Replace read-decide-write sequences with conditional atomic updates and check the affected row count.
  • Use row locks or Serializable isolation only where needed, with whole-transaction retries on SQLSTATE 40001 and deadlocks.
  • Acquire locks in a consistent order and keep transactions short.
  • Require idempotency keys on payment and creation endpoints and store results atomically.
  • Mark one-time tokens consumed in the same step that validates them.
  • Add parallel-request tests for every limited action to CI.
  • Monitor invariant violations, lock waits, deadlocks and serialisation failures.
  • Keep secrets out of build artefacts and scope short-lived tokens minimally.

Standards and references

Related NHI Mgmt Group resources: CWE Top 25 Guide · API Security Guide · Secure Software Development Lifecycle (SSDLC) Guide · Database Security Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.