Single-Packet Race Condition: Sub-Millisecond Web Exploitation
Wed May 27 2026
Category: Security Research
Introduction: Why Classic Race Condition Tests Fail
Race condition vulnerabilities exploit the gap between when an application checks a resource and when it uses it. This class is known as TOCTOU — Time-Of-Check-Time-Of-Use.
The theory sounds simple: send the same request multiple times simultaneously, bypass the check. In practice, network jitter makes this nearly impossible. Two HTTP requests can be separated by 10–50ms due to varying network conditions, while most race condition windows exist for only 2–20ms.
In 2023, James Kettle (PortSwigger) presented the "Smashing the State Machine" research at DEF CON 31, introducing a technique that fundamentally solves this problem: the Single-Packet Attack.
Sub-States: Where the Vulnerability Lives
For a race condition to be exploitable, the application must enter a brief "intermediate state" (sub-state).
Consider a gift card redemption flow:
1. Check balance → balance >= 100 ? ✓
2. [SUB-STATE ~5ms] → not yet deducted
3. Deduct balance → balance -= 100
If a second request can enter between steps 1 and 3 — while the balance hasn't been deducted yet — the card gets redeemed multiple times.
This window typically exists for 2–20 milliseconds.
The Single-Packet Technique
In the classic approach, each HTTP request travels over its own TCP connection. Network conditions cause requests to arrive at different milliseconds. The window is missed.
The single-packet solution:
HTTP/2 multiplexing allows multiple requests to be packed into a single TCP frame. All requests inside the same frame arrive at the server simultaneously — zero inter-request delay.
Last-frame synchronization:
- Prepare N-1 requests, hold them
- Prepare the final request
- Pack all of them into one TCP frame
- Send → all processed concurrently
CVE-2024-58248: nopCommerce Gift Card Race Condition
nopCommerce is a widely deployed open-source e-commerce platform. The gift card redemption endpoint's transaction sequence is not atomic.
Vulnerable code flow (simplified):
// GiftCardService.cs
public async Task<bool> RedeemGiftCard(string code, decimal amount)
{
var card = await _giftCardRepo.GetByCode(code);
// STEP 1: Check balance
if (card.RemainingAmount < amount)
return false;
// SUB-STATE EXISTS HERE (~3-8ms)
// card.RemainingAmount NOT YET updated in DB
// STEP 2: Deduct
card.RemainingAmount -= amount;
await _giftCardRepo.Update(card);
return true;
}
If multiple concurrent requests pass Step 1 before any of them reaches Step 2, all of them execute the deduction. A $100 gift card can be redeemed multiple times.
Exploit with Burp Suite:
1. Burp Suite → Repeater → Create a new tab group
2. Add the gift card redemption request 5 times to the group
3. Select "Send group (parallel)"
4. Ensure HTTP/2 is enabled for the target
5. Send → If all responses return 200 OK, exploit succeeded
Limit Overrun: Other Attack Scenarios
Race conditions extend far beyond gift cards:
1. Rate limit bypass:
POST /api/send-otp HTTP/2
# 5 requests/minute limit
# Send 5 requests simultaneously
# All processed before counter increments
2. Currency/balance manipulation:
Balance: $50
Send simultaneously: Transfer $40 × 3
Sub-state: all three checks pass ($50 >= $40)
Result: $120 transferred from a $50 balance
3. Single-use tokens:
Send email confirmation token 3 times simultaneously
All three pass before token is marked "used"
Automation with Turbo Intruder
For higher request volume, use Burp's Turbo Intruder extension:
def queueRequests(target, wordlists):
engine = RequestEngine(
endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=30,
pipeline=True
)
for i in range(30):
engine.queue(target.req)
engine.start(timeout=10)
def handleResponse(req, interesting):
if req.status == 200:
table.add(req)
Detection
Endpoints likely to contain race conditions:
- Any endpoint doing multi-step DB operations instead of atomic transactions
- Balance / credit / point mutation endpoints
- Single-use resource consumption (tokens, coupons, invite links)
- Response time anomalies under parallel load
Mitigation
1. Atomic database transactions with row-level locking:
BEGIN TRANSACTION;
SELECT balance FROM gift_cards WHERE code = ? FOR UPDATE;
UPDATE gift_cards
SET remaining = remaining - ?
WHERE code = ? AND remaining >= ?;
COMMIT;
2. Mutex / distributed lock:
using (await _lockService.AcquireLock($"giftcard:{code}"))
{
// Serialized execution — one thread at a time
await RedeemGiftCard(code, amount);
}
3. Idempotency keys:
Every redemption request must carry a single-use idempotency key. A second request with the same key is automatically rejected without re-executing the logic.
Conclusion
The single-packet technique moved race condition exploitation from theoretical to practical. Sub-millisecond windows are now reliably exploitable.
CVE-2024-58248 proved that this technique can cause significant financial losses in real-world e-commerce platforms. Any "check → use" flow that doesn't use atomic database operations is a potential race condition.
CVE: CVE-2024-58248
Platform: nopCommerce
Researcher: James Kettle / PortSwigger Research
Conference: DEF CON 31 (2023), Black Hat USA 2023
Reference: https://portswigger.net/research/smashing-the-state-machine
Introduction: Why Classic Race Condition Tests Fail
Race condition vulnerabilities exploit the gap between when an application checks a resource and when it uses it. This class is known as TOCTOU — Time-Of-Check-Time-Of-Use.
The theory sounds simple: send the same request multiple times simultaneously, bypass the check. In practice, network jitter makes this nearly impossible. Two HTTP requests can be separated by 10–50ms due to varying network conditions, while most race condition windows exist for only 2–20ms.
In 2023, James Kettle (PortSwigger) presented the "Smashing the State Machine" research at DEF CON 31, introducing a technique that fundamentally solves this problem: the Single-Packet Attack.
Sub-States: Where the Vulnerability Lives
For a race condition to be exploitable, the application must enter a brief "intermediate state" (sub-state).
Consider a gift card redemption flow:
1. Check balance → balance >= 100 ? ✓
2. [SUB-STATE ~5ms] → not yet deducted
3. Deduct balance → balance -= 100
If a second request can enter between steps 1 and 3 — while the balance hasn't been deducted yet — the card gets redeemed multiple times.
This window typically exists for 2–20 milliseconds.
The Single-Packet Technique
In the classic approach, each HTTP request travels over its own TCP connection. Network conditions cause requests to arrive at different milliseconds. The window is missed.
The single-packet solution:
HTTP/2 multiplexing allows multiple requests to be packed into a single TCP frame. All requests inside the same frame arrive at the server simultaneously — zero inter-request delay.
Last-frame synchronization:
- Prepare N-1 requests, hold them
- Prepare the final request
- Pack all of them into one TCP frame
- Send → all processed concurrently
CVE-2024-58248: nopCommerce Gift Card Race Condition
nopCommerce is a widely deployed open-source e-commerce platform. The gift card redemption endpoint's transaction sequence is not atomic.
Vulnerable code flow (simplified):
// GiftCardService.cs
public async Task<bool> RedeemGiftCard(string code, decimal amount)
{
var card = await _giftCardRepo.GetByCode(code);
// STEP 1: Check balance
if (card.RemainingAmount < amount)
return false;
// SUB-STATE EXISTS HERE (~3-8ms)
// card.RemainingAmount NOT YET updated in DB
// STEP 2: Deduct
card.RemainingAmount -= amount;
await _giftCardRepo.Update(card);
return true;
}
If multiple concurrent requests pass Step 1 before any of them reaches Step 2, all of them execute the deduction. A $100 gift card can be redeemed multiple times.
Exploit with Burp Suite:
1. Burp Suite → Repeater → Create a new tab group
2. Add the gift card redemption request 5 times to the group
3. Select "Send group (parallel)"
4. Ensure HTTP/2 is enabled for the target
5. Send → If all responses return 200 OK, exploit succeeded
Limit Overrun: Other Attack Scenarios
Race conditions extend far beyond gift cards:
1. Rate limit bypass:
POST /api/send-otp HTTP/2
# 5 requests/minute limit
# Send 5 requests simultaneously
# All processed before counter increments
2. Currency/balance manipulation:
Balance: $50
Send simultaneously: Transfer $40 × 3
Sub-state: all three checks pass ($50 >= $40)
Result: $120 transferred from a $50 balance
3. Single-use tokens:
Send email confirmation token 3 times simultaneously
All three pass before token is marked "used"
Automation with Turbo Intruder
For higher request volume, use Burp's Turbo Intruder extension:
def queueRequests(target, wordlists):
engine = RequestEngine(
endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=30,
pipeline=True
)
for i in range(30):
engine.queue(target.req)
engine.start(timeout=10)
def handleResponse(req, interesting):
if req.status == 200:
table.add(req)
Detection
Endpoints likely to contain race conditions:
- Any endpoint doing multi-step DB operations instead of atomic transactions
- Balance / credit / point mutation endpoints
- Single-use resource consumption (tokens, coupons, invite links)
- Response time anomalies under parallel load
Mitigation
1. Atomic database transactions with row-level locking:
BEGIN TRANSACTION;
SELECT balance FROM gift_cards WHERE code = ? FOR UPDATE;
UPDATE gift_cards
SET remaining = remaining - ?
WHERE code = ? AND remaining >= ?;
COMMIT;
2. Mutex / distributed lock:
using (await _lockService.AcquireLock($"giftcard:{code}"))
{
// Serialized execution — one thread at a time
await RedeemGiftCard(code, amount);
}
3. Idempotency keys:
Every redemption request must carry a single-use idempotency key. A second request with the same key is automatically rejected without re-executing the logic.
Conclusion
The single-packet technique moved race condition exploitation from theoretical to practical. Sub-millisecond windows are now reliably exploitable.
CVE-2024-58248 proved that this technique can cause significant financial losses in real-world e-commerce platforms. Any "check → use" flow that doesn't use atomic database operations is a potential race condition.
CVE: CVE-2024-58248
Platform: nopCommerce
Researcher: James Kettle / PortSwigger Research
Conference: DEF CON 31 (2023), Black Hat USA 2023
Reference: https://portswigger.net/research/smashing-the-state-machine
Giriş: Neden Klasik Race Condition Testleri Başarısız Olur?
Race condition (yarış koşulu) güvenlik açıkları, uygulamanın bir kaynağı kontrol ettiği an ile kullandığı an arasındaki zaman penceresini sömürür. Bu sınıf TOCTOU (Time-Of-Check-Time-Of-Use) olarak bilinir.
Teoride basit görünür: aynı isteği aynı anda birden fazla kez gönder, kontrol mekanizmasını atla. Pratikte ise ağ gecikmesi (jitter) bu saldırıyı neredeyse imkânsız kılar. İki HTTP isteği, farklı ağ koşulları nedeniyle birbirinden 10–50ms sapabilir. Çoğu açık yalnızca 2–20ms'lik bir pencerede mevcuttur.
2023 yılında James Kettle (PortSwigger), DEF CON 31'de sunduğu "Smashing the State Machine" araştırmasıyla bu sorunu temelden çözen bir teknik geliştirdi: Single-Packet Attack.
Sub-State: Açığın Yaşadığı Yer
Race condition'ların çalışabilmesi için uygulamanın kısa süreli bir "ara durum"a (sub-state) girmesi gerekir.
Bir hediye kartı (gift card) redemption akışını düşünelim:
1. Bakiyeyi kontrol et → balance >= 100 ? ✓
2. [SUB-STATE — ~5ms] → henüz düşülmedi
3. Bakiyeyi düş → balance -= 100
Eğer ikinci bir istek, "1" ve "3" adımları arasına girebilirse — yani bakiye henüz düşülmemişken tekrar kontrol başarılı olursa — kart birden fazla kez kullanılır.
Bu pencere genellikle 2–20 milisaniye arasındadır.
Single-Packet Tekniği
Klasik yaklaşımda her HTTP isteği ayrı bir TCP bağlantısı üzerinden gönderilir. Ağ koşulları nedeniyle istekler farklı milisaniyede sunucuya ulaşır. Pencere kaçırılır.
Single-packet tekniğinin çözümü:
HTTP/2 multiplexing sayesinde birden fazla request, tek bir TCP paketine sığdırılabilir. Aynı frame içindeki tüm requestler sunucuya aynı anda ulaşır — aralarında sıfır gecikme.
Son-frame senkronizasyonu (Last-Frame Sync):
- N-1 adet isteği hazırla, gönderme
- Son isteği de hazırla
- Hepsini tek bir TCP frame'e yükle
- Gönder → tümü eş zamanlı işlenir
CVE-2024-58248: nopCommerce Gift Card Race Condition
nopCommerce, yaygın olarak kullanılan açık kaynaklı bir e-ticaret platformudur. Hediye kartı kullanım uç noktasındaki işlem dizisi atomik değildir.
Savunmasız kod akışı (sadeleştirilmiş):
// GiftCardService.cs
public async Task<bool> RedeemGiftCard(string code, decimal amount)
{
var card = await _giftCardRepo.GetByCode(code);
// STEP 1: Check balance
if (card.RemainingAmount < amount)
return false;
// SUB-STATE EXISTS HERE (~3-8ms)
// card.RemainingAmount NOT YET updated in DB
// STEP 2: Deduct
card.RemainingAmount -= amount;
await _giftCardRepo.Update(card);
return true;
}
Veritabanı kaydı güncellenmeden önce aynı anda birden fazla istek Step 1'i geçerse, tümü Step 2'yi çalıştırır. 100$ değerinde bir kart birden fazla kez kullanılabilir.
Burp Suite ile exploit:
1. Burp Suite → Repeater → Yeni bir sekme grubu oluştur
2. Hediye kartı redemption isteğini sekme grubuna 5 kez ekle
3. "Send group (parallel)" seçeneğini kullan
4. HTTP/2 etkin olduğundan emin ol
5. Gönder → Tüm yanıtlar 200 OK dönüyorsa başarılı
Limit Overrun: Diğer Saldırı Senaryoları
Race condition yalnızca gift card'larla sınırlı değildir:
1. Rate limit bypass:
POST /api/send-otp HTTP/2
# 5 istek/dakika limiti varsa, 5 isteği aynı anda gönder
# Tümü limit sayacı artmadan işlenebilir
2. Para birimi işlemleri:
Bakiye: $50
Aynı anda gönder: Transfer $40 × 3
Sub-state'de 3 × kontrol geçer: $50 >= $40 ✓
Sonuç: $120 transfer edilir, $50 bakiyeden
3. Tek kullanımlık token'lar:
Email doğrulama token'ını aynı anda 3 kez kullan
Token "used" olarak işaretlenmeden önce tümü geçer
Turbo Intruder ile Otomasyon
Daha fazla eş zamanlı istek için Burp'ün Turbo Intruder eklentisi kullanılabilir:
def queueRequests(target, wordlists):
engine = RequestEngine(
endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=30, # 30 request, 1 connection
pipeline=True
)
for i in range(30):
engine.queue(target.req)
engine.start(timeout=10)
def handleResponse(req, interesting):
if req.status == 200:
table.add(req)
Tespit
Race condition açıklarını tespit etmek için:
- Atomik işlemler yerine birden fazla DB sorgusu yapan uç noktalar
- Bakiye/kredi/puan değiştiren endpoint'ler
- Tek kullanımlık kaynak (token, kupon, davet linki) kullanan işlemler
- Response süresinde ani değişiklikler
Önlem
1. Veritabanı düzeyinde atomik işlemler:
BEGIN TRANSACTION;
SELECT balance FROM gift_cards WHERE code = ? FOR UPDATE;
-- Lock row — concurrent reads blocked
UPDATE gift_cards SET remaining = remaining - ?
WHERE code = ? AND remaining >= ?;
COMMIT;
2. Mutex / distributed lock:
using (await _lockService.AcquireLock($"giftcard:{code}"))
{
// Only one thread enters at a time
await RedeemGiftCard(code, amount);
}
3. Idempotency key'ler:
Her redemption isteği, tek kullanımlık bir idempotency key taşımalı. Aynı key ile gelen ikinci istek otomatik reddedilmeli.
Sonuç
Single-packet tekniği, race condition saldırılarını teorik olmaktan çıkarıp pratik bir tehdit haline getirdi. Milisaniye altı pencereler artık güvenilir biçimde istismar edilebilir durumdadır.
CVE-2024-58248, bu tekniğin gerçek dünya e-ticaret platformlarında ciddi mali kayıplara yol açabileceğini kanıtladı. Herhangi bir "kontrol et → kullan" akışı, atomik olmayan veritabanı işlemleri içeriyorsa potansiyel bir race condition barındırır.
CVE: CVE-2024-58248
Platform: nopCommerce
Araştırmacı: James Kettle / PortSwigger Research
Konferans: DEF CON 31 (2023), Black Hat USA 2023