Race TOCTOU (CWE-367) : état validé puis utilisé dans des opérations non atomiques — changements d'état entre la vérification et l'utilisation permettent des doubles dépenses.
TL;DR
UPDATE WHERE condition atomique ou SELECT FOR UPDATE — jamais SELECT + UPDATE séparésLe TOCTOU (Time-of-Check to Time-of-Use, CWE-367) est le sous-type de race condition le plus répandu dans les systèmes d'exploitation et les applications web. Le pattern est mécaniquement simple : une application évalue une précondition à un moment (la vérification), puis effectue une action dépendant de cette précondition à un moment ultérieur (l'utilisation). Entre ces deux moments, un autre thread, processus ou requête concurrente peut modifier l'état que la vérification a évalué — invalidant l'hypothèse sur laquelle l'utilisation repose.
Dans les applications web, l'état autoritatif réside en base de données. Toute séquence SELECT-puis-UPDATE où le résultat du SELECT conditionne l'UPDATE est un TOCTOU potentiel. La vérification (SELECT) et l'utilisation (UPDATE) sont deux allers-retours séparés vers la base, et toute requête concurrente qui écrit dans la même ligne pendant cette fenêtre invalide la vérification.
Le TOCTOU est classifié sous CWE-367, enfant de CWE-362. OWASP A04:2021 (Insecure Design) le couvre sous la conception défectueuse de machine à états.
Le TOCTOU de base de données suit une structure à trois étapes prévisibles :
1. VÉRIF : SELECT state FROM resource WHERE id = X → state = 'valid'
2. [FENÊTRE TOCTOU — transaction concurrente lit le même 'valid']
3. ACTION : UPDATE resource SET state = 'consumed' WHERE id = X AND state = 'valid'Les deux requêtes concurrentes lisent state = 'valid' et committent toutes les deux leur UPDATE.
Le TOCTOU filesystem suit le même pattern :
1. VÉRIF : stat("/upload/FILE.TXT") → extension = .txt (pas JSP, skip compile)
2. [FENÊTRE TOCTOU — upload FILE.JSP de l'attaquant écrase le même chemin]
3. ACTION : process("/upload/FILE.TXT") → lit contenu JSP, compile et exécuteApache Tomcat CVE-2024-50379 exploite exactement ce TOCTOU filesystem. La vérification d'extension voit .txt mais l'étape de compilation trouve du bytecode JSP. GET /file.jsp exécute avec les privilèges du service Tomcat.
# CVE-2024-50379 class — PoC TOCTOU filesystem sur FS insensible à la casse
import asyncio, httpx
async def tomcat_toctou_race(target: str, upload_endpoint: str, jsp_payload: bytes):
async with httpx.AsyncClient(http2=True, verify=False) as client:
await client.get(target + "/") # Réchauffement
harmless = client.post(upload_endpoint,
files={"file": ("payload.txt", b"contenu bénin", "text/plain")})
weaponized = client.post(upload_endpoint,
files={"file": ("PAYLOAD.JSP", jsp_payload, "application/x-jsp")})
r1, r2 = await asyncio.gather(harmless, weaponized)
rce = await client.get(target + "/payload.jsp")
return rce.text # "uid=" dans la réponse confirme RCE| Variante | Contexte | CVE exemple | CVSS |
|---|---|---|---|
| TOCTOU filesystem | FS insensible casse + handler upload | CVE-2024-50379 (Tomcat), CVE-2024-7344 (Docker) | 7.0–9.8 |
| Élévation de privilèges noyau | Binaire SUID, race syscall | CVE-2024-30088 (Windows), CVE-2025-38352 (Linux) | 7.0–7.4 |
| TOCTOU hyperviseur | Mémoire partagée VM guest–host | CVE-2025-22224 (VMware ESXi) | 9.3 |
| TOCTOU base de données | SELECT puis UPDATE non atomique | Races web fintech/e-commerce courantes | Variable |
| TOCTOU cache | Lookup → compute → set sans verrou | Revalidation CDN (CVE-2025-32421 class) | 5.4–7.5 |
| TOCTOU lien symbolique | Extraction d'archive, pipeline de build | CVE-2024-7344 (Docker buildkit) | 7.0 |
CVE-2024-30088 — Noyau Windows (CISA KEV, juin 2024, CVSS 7.0)
TOCTOU dans NtQueryInformationToken permettant l'escalade locale vers SYSTEM. Ajouté à la CISA KEV en juin 2024 avec exploitation confirmée dans la nature.
CVE-2025-22224 — VMware ESXi/Workstation (CISA KEV, mars 2025, CVSS 9.3) Débordement de heap TOCTOU dans le sous-système VMCI permettant à un processus VM invité d'échapper vers l'hôte hyperviseur. Exploité dans des campagnes actives avant le correctif de mars 2025.
CVE-2024-50379 + CVE-2024-56337 — Apache Tomcat (CVSS 9.8)
TOCTOU de compilation JSP sur filesystem insensible à la casse. Deux uploads concurrents créent une race où la vérification d'extension voit .txt mais la compilation exécute du bytecode JSP. CVE-2024-56337 était un correctif incomplet contournable. Corrigé dans Tomcat 11.0.2 / 10.1.34 / 9.0.98.
CVE-2024-7344 — Docker Buildkit Symlink TOCTOU (CVSS 7.0) L'exécuteur BuildKit vérifiait si un chemin pointait vers un fichier régulier avant traitement. Un attaquant avec accès au contexte de build pouvait racer la création d'un lien symbolique contre la vérification, causant l'accès à des fichiers hors du contexte de build prévu.
CVE-2025-38352 — Noyau Linux POSIX Timer TOCTOU (CISA KEV, septembre 2025, CVSS 7.4) TOCTOU dans la gestion des timers POSIX CPU permettant l'élévation de privilèges locale. Troisième TOCTOU noyau dans la CISA KEV en 15 mois.
/redeem/{token}, POST /apply/{coupon}, POST /withdraw, POST /confirm/{token}.# Pattern de preuve TOCTOU read-race-read
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 {"successes": successes, "pre": pre_state, "post": post_state,
"toctou_confirme": successes > 1}BreachVex détecte les TOCTOU de base de données via plusieurs techniques complémentaires : analyse structurelle des patterns d'URL, bursts de requêtes concurrentes, et vérification d'état. La détection des TOCTOU filesystem utilise des paires d'uploads concurrents avec noms à casse variante sur les cibles Windows/macOS.
-- VULNÉRABLE : deux étapes check + update — fenêtre TOCTOU entre elles
SELECT is_used FROM tokens WHERE value = $1;
UPDATE tokens SET is_used = TRUE WHERE value = $1;
-- CORRIGÉ : UPDATE conditionnel atomique — pas d'aller-retour entre check et action
UPDATE tokens
SET is_used = TRUE, used_by = $2, used_at = NOW()
WHERE value = $1 AND is_used = FALSE
RETURNING id; -- 0 lignes = déjà utilisé# SQLAlchemy — verrou en écriture au niveau ligne ferme la fenêtre TOCTOU
with session.begin():
token = session.execute(
select(Token)
.where(Token.value == token_value, Token.is_used == False)
.with_for_update() # Acquiert verrou écriture — SELECT concurrents bloquent
).scalar_one_or_none()
if token is None:
raise ValueError("Token invalide ou déjà utilisé")
token.is_used = True
token.used_by = user_id
# Verrou maintenu jusqu'au commit — fenêtre TOCTOU éliminée@Entity
public class Coupon {
@Id private Long id;
private boolean used;
@Version
private Long version; // Auto-incrémenté à chaque UPDATE
}
@Transactional(isolation = Isolation.SERIALIZABLE)
public void redeemCoupon(Long couponId, Long userId) {
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException("Coupon non trouvé"));
if (coupon.isUsed()) {
throw new IllegalStateException("Coupon déjà utilisé");
}
coupon.setUsed(true);
coupon.setRedeemedBy(userId);
// Si version changée concurremment, lève OptimisticLockException — l'appelant réessaie
couponRepository.save(coupon);
}CVE-2024-30088, CVE-2025-22224 et CVE-2025-38352 — les trois entrées CISA KEV TOCTOU — ont été exploitées dans la nature dans les semaines suivant la divulgation publique. Patcher les CVE TOCTOU noyau et hyperviseur comme intervention d'urgence, pas en maintenance planifiée.
TOCTOU signifie Time-of-Check to Time-of-Use (CWE-367). Il décrit une race condition où une application vérifie une précondition à un moment donné, puis agit sur cette vérification à un moment ultérieur — avec une fenêtre où la précondition peut changer. Si un attaquant modifie l'état pendant cette fenêtre, l'action s'exécute sur de fausses hypothèses.
CVE-2024-50379 (CVSS 9.8) est un TOCTOU dans la compilation JSP d'Apache Tomcat sur les systèmes de fichiers insensibles à la casse. Tomcat vérifie l'extension du nom de fichier pour déterminer si la compilation JSP est nécessaire. Un attaquant race deux uploads concurrents — FILE.JSP (weaponized) et file.txt (bénin) — vers le même chemin. La vérification voit .txt ; au moment de la compilation, le contenu JSP est sur le disque. Résultat : RCE non authentifié via GET /file.jsp. Corrigé dans Tomcat 11.0.2 / 10.1.34 / 9.0.98.
CVE-2024-30088 (noyau Windows, CVSS 7.0) : race NtQueryInformationToken check contre une modification pour élever vers SYSTEM. CVE-2025-22224 (VMware ESXi, CVSS 9.3) : débordement de heap VMCI via race check de taille contre écriture buffer — VM escape. CVE-2025-38352 (noyau Linux, CVSS 7.4) : TOCTOU POSIX CPU timer permettant élévation de privilèges locale. Les trois confirmés exploités dans la nature avant les correctifs.
Utiliser @Transactional(isolation = Isolation.SERIALIZABLE) sur la méthode service, ou @Version sur l'entité pour le verrouillage optimiste. SERIALIZABLE garantit qu'aucune transaction concurrente ne modifie la ligne entre la vérification et la mise-à-jour. @Version utilise une colonne de version incrémentale — si elle change entre lecture et écriture, l'UPDATE affecte 0 lignes et l'application réessaie.
Le TOCTOU (CWE-367) race une condition de garde explicite sur une ressource existante et entièrement initialisée — solde >= montant, is_used == false. Le dépassement de limite race un incrément de compteur : le compteur existe mais la vérification et l'incrément ne sont pas atomiques. Le TOCTOU a une étape de vérification nommée qui devient obsolète ; le dépassement de limite manque simplement d'atomicité sur une mutation de compteur. Les deux partagent la même correction — UPDATE conditionnel atomique — mais le TOCTOU admet aussi SELECT FOR UPDATE comme solution basée sur un verrou.
L'isolation READ COMMITTED garantit que chaque instruction voit un instantané cohérent au démarrage de l'instruction, mais deux instructions séparées — SELECT puis UPDATE — sont chacune indépendamment cohérentes. Entre le SELECT (vérification) et l'UPDATE (utilisation), une transaction concurrente peut commiter une modification sur la ligne. Seule l'isolation SERIALIZABLE ou SELECT FOR UPDATE l'empêche : SERIALIZABLE détecte le conflit write-write et abandonne une transaction ; SELECT FOR UPDATE acquiert un verrou d'écriture au niveau ligne qui bloque le SELECT concurrent jusqu'au commit.
SELECT FOR UPDATE prévient le TOCTOU de base de données quand utilisé correctement dans une transaction, mais présente trois modes d'échec : (1) avec isolation READ COMMITTED et un prédicat non unique, les nouvelles lignes insérées par des transactions concurrentes ne sont pas verrouillées ; (2) si le SELECT est effectué hors d'une transaction, le verrou se libère immédiatement ; (3) pour le TOCTOU filesystem (classe CVE-2024-50379), SELECT FOR UPDATE est sans rapport — les opérations filesystem n'ont pas de mécanisme de verrou SQL. Pour les races filesystem, la correction est un rename(2) atomique après validation hors du webroot.
Le TOCTOU de base de données race deux instructions SQL dans le modèle de transaction de l'application — corrigeable avec SELECT FOR UPDATE ou UPDATE WHERE atomique. Le TOCTOU filesystem race des opérations au niveau OS : stat()-puis-open(), ou vérification-extension-puis-compilation (CVE-2024-50379). Les races filesystem ne peuvent pas être prévenues avec des verrous SQL. La correction est architecturale : ne jamais écrire vers un chemin web-accessible avant la fin de la validation — uploader vers un répertoire temp non-webroot, valider avec O_NOFOLLOW pour prévenir les races de liens symboliques, puis rename(2) atomiquement vers la destination finale.
Le TOCTOU filesystem atteignant RCE (CVE-2024-50379 Tomcat : CVSS 9.8) score significativement plus haut que le TOCTOU de base de données (typiquement CVSS 5.9–7.5) car la Complexité d'Attaque est plus faible sur les systèmes de fichiers insensibles à la casse et l'Impact inclut la compromission complète CIA. Le TOCTOU de base de données nécessite généralement une authentification et l'impact se limite à la manipulation de données. Le TOCTOU noyau (CVE-2025-22224 VMware : CVSS 9.3) score élevé car l'accès local est suffisant et le VM escape atteint la compromission de l'hyperviseur.