# Concurrent shared mutable state races

Shared templates, maps or caches written by one path while read or executed by another, without locking

_Area: Web business logic and race conditions. Seen in 2 disclosed reports; latest 2026-06-24. Updated 2026-10-25._

## How it works
A single object (a template, a map, a cache) is shared across concurrent paths. One path writes it while another reads or executes it, with no lock. The code assumes each request or each peer gets its own copy, or that writes complete before reads begin. Neither holds: goroutines interleave, so a reader sees a half-written tree, or two writers collide on a map that Go does not protect. The same flaw appears when a dedup cache is keyed on a value that does not commit to the full body: a rejected variant poisons the key and blocks the valid one [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md).

## Where it shows up
- Package-level `template.New(...)` singletons where per-request `Parse` runs before `Execute` [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-7fq5-7wr8-rjwj.md)
- `errgroup.Go()` or goroutine fan-out that writes request-scoped maps/slices (`ctx.files`, `diskToOriginal`) [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vp73-vjw8-8f32.md)
- Dedup/sent-hash caches inserted before validation and not removed on failure [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md)
- Cache keys that are hashes not committing to the full body (txid vs auth_digest) [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md)
- Absence of `sync.Mutex`/`Lock` around a shared field; grep for it

## How to review
Find every object with package or request scope that is written after startup. For each, confirm either (a) it is immutable after init, (b) every write and read is under one lock, or (c) each goroutine owns a private copy. For caches: the invariant is that an entry is only trusted after the object it keys has passed validation, and failed writes remove the entry. Check that the cache key commits to everything the consumer relies on [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md).

## Variants seen
- Shared template mutated by Parse while Execute reads it, contaminating cross-request commands [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-7fq5-7wr8-rjwj.md)
- Fan-out goroutines writing shared context maps, crashing on concurrent map write [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vp73-vjw8-8f32.md)
- Insert-before-validate dedup cache poisoning via a non-committing hash [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md)

## Impact and severity
Unauthenticated process crash (DoS) [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vp73-vjw8-8f32.md), cross-request command contamination [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-7fq5-7wr8-rjwj.md), and node sync stall from a single peer [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md). Severity rises when the race is reachable pre-auth or from one remote peer, and when contamination crosses request boundaries rather than only crashing.

## Why fixes fail
Fixing only the crash (recover) leaves contamination; fixing only the template leaves the map writes. Each shared object needs its own ownership or lock decision.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-4m69-67m6-prqp.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-7fq5-7wr8-rjwj.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-vp73-vjw8-8f32.md
