Time-of-Check to Time-of-Use flaw where state is validated and then used in separate non-atomic operations, allowing state changes between the two.
TL;DR
UPDATE WHERE condition or SELECT FOR UPDATE — never separate SELECT + UPDATETOCTOU (Time-of-Check to Time-of-Use, CWE-367) is the most prevalent subtype of race condition in both operating systems and web applications. The pattern is mechanically simple: an application evaluates a precondition at one moment (the check), then performs an action contingent on that precondition at a later moment (the use). Between these two moments, another thread, process, or concurrent request can change the state the check evaluated — invalidating the assumption the use relies on.
In web applications, the authoritative state lives in a database. Every SELECT-then-UPDATE sequence where the SELECT result drives the UPDATE condition is a potential TOCTOU. The check (SELECT) and use (UPDATE) are two separate round-trips to the database, and any concurrent request that writes to the same row during that window defeats the check. At the kernel level, the same pattern appears as stat()-then-open() sequences in filesystem access and as privilege checks followed by privileged operations in syscall handlers.
TOCTOU is classified under CWE-367, a child of CWE-362 (concurrent execution with shared resource). OWASP A04:2021 (Insecure Design) covers it under improper state machine design — the application's state machine was designed without guaranteeing atomic transitions between the check and use steps.
The database TOCTOU follows a predictable three-step structure:
1. CHECK: SELECT state FROM resource WHERE id = X → state = 'valid'
2. [TOCTOU WINDOW — concurrent transaction reads same 'valid' state]
3. USE: UPDATE resource SET state = 'consumed' WHERE id = X AND state = 'valid'Both concurrent requests read state = 'valid' and both commit their UPDATE. The resource is consumed twice.
The filesystem TOCTOU follows the same pattern with file operations:
1. CHECK: stat("/upload/FILE.TXT") → extension = .txt (not JSP, skip compilation)
2. [TOCTOU WINDOW — attacker's FILE.JSP upload overwrites same path on case-insensitive FS]
3. USE: process("/upload/FILE.TXT") → reads JSP content, compiles and executesApache Tomcat CVE-2024-50379 exploits exactly this filesystem TOCTOU. Tomcat's JSP compilation on case-insensitive file systems checks the filename to determine if compilation is needed. Two concurrent uploads to the same logical path — FILE.JSP and file.txt — create a race where Tomcat's extension check sees .txt but the compile step finds JSP bytecode. A subsequent GET /file.jsp executes the compiled JSP with Tomcat's service account privileges.
# CVE-2024-50379 class — filesystem TOCTOU PoC on case-insensitive FS
import asyncio
import httpx
async def tomcat_toctou_race(target: str, upload_endpoint: str, jsp_payload: bytes):
"""Race upload of FILE.JSP and file.txt to same case-insensitive FS path."""
async with httpx.AsyncClient(http2=True, verify=False) as client:
await client.get(target + "/") # Warm connection
harmless = client.post(upload_endpoint,
files={"file": ("payload.txt", b"benign content", "text/plain")})
weaponized = client.post(upload_endpoint,
files={"file": ("PAYLOAD.JSP", jsp_payload, "application/x-jsp")})
r1, r2 = await asyncio.gather(harmless, weaponized)
# Trigger JSP compilation and execution
rce = await client.get(target + "/payload.jsp")
return rce.text # "uid=" in response confirms RCE| Variant | Context | Example CVE | CVSS |
|---|---|---|---|
| Filesystem TOCTOU | Case-insensitive FS + upload handler | CVE-2024-50379 (Tomcat), CVE-2024-7344 (Docker) | 7.0–9.8 |
| Kernel privilege escalation | SUID binary, syscall race | CVE-2024-30088 (Windows), CVE-2025-38352 (Linux) | 7.0–7.4 |
| Hypervisor TOCTOU | VM guest–host shared memory | CVE-2025-22224 (VMware ESXi) | 9.3 |
| Database TOCTOU | SELECT then non-atomic UPDATE | Most web fintech/e-commerce races | Varies |
| Cache TOCTOU | Lookup → compute → set without lock | CDN revalidation (CVE-2025-32421 class) | 5.4–7.5 |
| Symlink TOCTOU | Archive extraction, build pipeline | CVE-2024-7344 (Docker buildkit) | 7.0 |
Database TOCTOU is the most common web variant. Any ORM pattern that reads a row, checks a field, then updates is vulnerable. The read-into-memory → modify → save-back pattern has a race window on every ORM framework: Rails, Django, Hibernate, Mongoose.
Kernel TOCTOU vulnerabilities (CVE-2024-30088, CVE-2025-38352) appear regularly because kernel code frequently performs security decisions in one function and acts in another, with context switches possible between them. Three kernel-level TOCTOU CVEs reached the CISA KEV catalog between June 2024 and September 2025.
Hypervisor TOCTOU (CVE-2025-22224) is the highest-impact class: a guest VM process races a size check in the host-side VMCI driver against a buffer write, achieving heap overflow on the hypervisor host. VM escape from a CVSS 9.3 TOCTOU.
CVE-2024-30088 — Windows Kernel (CISA KEV, June 2024, CVSS 7.0)
A TOCTOU in NtQueryInformationToken processing allowed local privilege escalation to SYSTEM. Added to CISA's Known Exploited Vulnerabilities catalog in June 2024 with confirmed in-the-wild exploitation. Patched in June 2024 Patch Tuesday.
CVE-2025-22224 — VMware ESXi/Workstation (CISA KEV, March 2025, CVSS 9.3)
A TOCTOU heap overflow in VMware's VMCI (Virtual Machine Communication Interface) subsystem enabled guest VM process escape to the hypervisor host. The race occurs between a size validation check and a subsequent memory copy — a guest with access to the VMCI device wins the race to corrupt host memory. Exploited in active campaigns targeting cloud and VDI environments before the March 2025 advisory.
CVE-2024-50379 + CVE-2024-56337 — Apache Tomcat (CVSS 9.8)
JSP compilation TOCTOU on case-insensitive file systems. Two concurrent uploads to the same logical path create a race where the extension check sees .txt but the compilation step executes JSP bytecode. GET /file.jsp triggers execution with Tomcat's service privileges. CVE-2024-56337 was an incomplete fix bypassable with alternative case permutations. Fixed in Tomcat 11.0.2 / 10.1.34 / 9.0.98.
CVE-2024-7344 — Docker Buildkit Symlink TOCTOU (CVSS 7.0)
Docker's BuildKit executor checked whether a path pointed to a regular file before processing. An attacker with build context access could race a symlink creation against the check, causing the build step to process a file outside the intended build context — container escape in Docker-in-Docker environments.
CVE-2025-38352 — Linux Kernel POSIX Timer TOCTOU (CISA KEV, September 2025, CVSS 7.4)
A TOCTOU in POSIX CPU timer handling allowed local privilege escalation. Added to the CISA KEV catalog in September 2025 — the third kernel-level TOCTOU in the catalog within 15 months.
/redeem/{token}, POST /apply/{coupon}, POST /withdraw, POST /confirm/{token}.For filesystem TOCTOU:
test.TXT and test.jsp)..jsp path. Command output in the response confirms the race.# Read-race-read TOCTOU proof pattern
async def toctou_proof(pre_url: str, race_url: str, race_body: dict,
post_url: str, headers: dict, n: int = 20):
async with httpx.AsyncClient(http2=True, verify=False) as client:
pre_state = (await client.get(pre_url, headers=headers)).json()
tasks = [client.post(race_url, headers=headers, json=race_body) for _ in range(n)]
responses = await asyncio.gather(*tasks)
successes = sum(1 for r in responses if r.status_code == 200)
post_state = (await client.get(post_url, headers=headers)).json()
return {
"race_successes": successes,
"state_before": pre_state,
"state_after": post_state,
"toctou_confirmed": successes > 1,
}BreachVex detects database TOCTOU through complementary techniques: structural URL pattern analysis, concurrent request bursts, and state verification. Filesystem TOCTOU detection uses concurrent case-variant upload pairs against Windows/macOS-fingerprinted targets.
-- VULNERABLE: two-step check + update — TOCTOU window between them
SELECT is_used FROM tokens WHERE value = $1;
UPDATE tokens SET is_used = TRUE WHERE value = $1;
-- FIXED: atomic conditional UPDATE — no round-trip between check and use
UPDATE tokens
SET is_used = TRUE, used_by = $2, used_at = NOW()
WHERE value = $1 AND is_used = FALSE
RETURNING id; -- 0 rows returned = already used# SQLAlchemy — row-level write lock closes the TOCTOU window
with session.begin():
token = session.execute(
select(Token)
.where(Token.value == token_value, Token.is_used == False)
.with_for_update() # Acquires write lock — concurrent SELECTs block
).scalar_one_or_none()
if token is None:
raise ValueError("Token invalid or already used")
token.is_used = True
token.used_by = user_id
# Lock held until commit — TOCTOU window eliminated@Entity
public class Coupon {
@Id private Long id;
private boolean used;
@Version
private Long version; // Auto-incremented on each UPDATE
}
@Transactional(isolation = Isolation.SERIALIZABLE)
public void redeemCoupon(Long couponId, Long userId) {
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException("Coupon not found"));
if (coupon.isUsed()) {
throw new IllegalStateException("Coupon already redeemed");
}
coupon.setUsed(true);
coupon.setRedeemedBy(userId);
// If version changed concurrently, throws OptimisticLockException — caller retries
couponRepository.save(coupon);
}CVE-2024-30088, CVE-2025-22224, and CVE-2025-38352 — all three CISA KEV TOCTOU entries — were exploited in the wild within weeks of public disclosure. Patch kernel and hypervisor TOCTOU CVEs as emergency response, not scheduled maintenance.
TOCTOU stands for Time-of-Check to Time-of-Use (CWE-367). It describes a race condition where an application checks a precondition at one point in time, then acts on that check at a later point — with a window in between where the precondition can change. If an attacker modifies state during that window, the action executes under false assumptions.
CVE-2024-50379 (CVSS 9.8) is a TOCTOU race in Apache Tomcat JSP compilation on case-insensitive file systems. Tomcat checks the filename extension to determine if JSP compilation is needed. An attacker races two concurrent uploads — FILE.JSP (weaponized) and file.txt (benign) — to the same case-insensitive path. The check sees .txt; by the time compilation runs, JSP content is on disk. The result is unauthenticated RCE via GET /file.jsp. Fixed in Tomcat 11.0.2 / 10.1.34 / 9.0.98.
TOCTOU (CWE-367) is a specific subtype of race condition (CWE-362). All TOCTOU flaws are race conditions, but not all race conditions are TOCTOU. TOCTOU specifically describes a check-before-use pattern where the check and use are non-atomic. Other race conditions include single-endpoint state collisions and partial construction windows, which don't necessarily have an explicit check-and-use pattern.
CVE-2024-30088 (Windows Kernel, CVSS 7.0): races NtQueryInformationToken check against modification to escalate to SYSTEM. CVE-2025-22224 (VMware ESXi, CVSS 9.3): VMCI heap overflow via racing size check against buffer write — VM escape. CVE-2025-38352 (Linux kernel, CVSS 7.4): POSIX CPU timer TOCTOU enables local privilege escalation. All three confirmed exploited in the wild before patching.
Use @Transactional(isolation = Isolation.SERIALIZABLE) on the service method, or @Version on the entity for optimistic locking. SERIALIZABLE guarantees no concurrent transaction modifies the row between check and update. @Version uses an incrementing version column — if it changed between read and write, the UPDATE affects 0 rows and the application retries.
TOCTOU (CWE-367) races an explicit guard condition on an existing, fully initialized resource — balance >= amount, is_used == false. Limit overrun (CWE-362 without the guard pattern) races a counter increment: the counter exists but the check-and-increment are not atomic. TOCTOU has a named check step that becomes stale; limit overrun simply lacks atomicity on a counter mutation. Both share the same fix — atomic conditional UPDATE — but TOCTOU also admits SELECT FOR UPDATE as a lock-based solution.
READ COMMITTED isolation ensures each statement sees a consistent snapshot at statement start, but two separate statements — SELECT then UPDATE — are each independently consistent. Between the SELECT (check) and UPDATE (use), a concurrent transaction can commit a change to the row. Both the attacker's SELECT and the victim's SELECT see the same pre-change state because the modification hasn't committed yet. Only SERIALIZABLE isolation or SELECT FOR UPDATE prevents this: SERIALIZABLE detects the write-write conflict and aborts one transaction; SELECT FOR UPDATE holds a row-level write lock that blocks the concurrent SELECT until the first transaction commits.
SELECT FOR UPDATE prevents database TOCTOU when used correctly within a transaction, but has three failure modes: (1) if the transaction isolation is READ COMMITTED and the query uses a non-unique predicate, new rows inserted by concurrent transactions are not locked; (2) if the application does the SELECT outside a transaction boundary, the lock releases immediately; (3) for filesystem TOCTOU (CVE-2024-50379 class), SELECT FOR UPDATE is irrelevant — filesystem operations have no SQL lock mechanism. For filesystem races, the fix is atomic rename(2) after out-of-webroot validation.
Database TOCTOU races two SQL statements within the application's transaction model — fixable with SELECT FOR UPDATE or atomic UPDATE WHERE. Filesystem TOCTOU races OS-level operations: stat()-then-open(), or check-extension-then-compile (CVE-2024-50379). Filesystem races cannot be prevented with SQL locks. The fix is architectural: never write to a web-accessible path before validation is complete — upload to a non-webroot temp directory, validate with O_NOFOLLOW to prevent symlink races, then rename(2) atomically to the final destination. rename(2) is atomic on POSIX filesystems; the file either appears at the destination or it doesn't — there is no intermediate state.
Filesystem TOCTOU achieving RCE (CVE-2024-50379 Tomcat: CVSS 9.8) scores significantly higher than database TOCTOU (typically CVSS 5.9–7.5) because the Attack Complexity is lower on case-insensitive filesystems and the Impact includes full Confidentiality + Integrity + Availability compromise (RCE). Database TOCTOU is usually rated CVSS 5.9–7.5 because it requires authentication, and the impact is limited to data manipulation rather than code execution. Kernel TOCTOU (CVE-2025-22224 VMware: CVSS 9.3) scores high because local access is sufficient and VM escape achieves hypervisor compromise.