shared × unstructured — bad data written permanently, and it spreads

NaN Poisons a Shared Aggregate

A single divide-by-zero feeds NaN into a shared running total; NaN is absorbing, so every later reader gets garbage forever.

01the recipe

In the wild

example.py
# SMELL: a /0 produces NaN that lands in a shared accumulator.
# (divide-by-zero x threading / mutexes)
import math
stats = {"sum": 0.0}
def record(latency, n):
    with lock:
        stats["sum"] += latency / n      # n == 0 -> NaN; NaN + x == NaN
# one bad sample (n == 0) makes stats["sum"] NaN forever; every reader of the
# shared aggregate now gets NaN -- the dashboard is permanently wrong.

# RIGHT: reject the non-finite value before it touches shared state.
def record(latency, n):
    if n == 0: return
    v = latency / n
    if not math.isfinite(v): return
    with lock:
        stats["sum"] += v
NaN is absorbing: once a single divide-by-zero feeds NaN into the shared running total, every later add stays NaN and every reader downstream sees garbage. The lock makes the write thread-safe but cannot un-poison the value -- the corruption is permanent and shared. Validate the numeric domain before it crosses into shared state.
// observed
poisoned: one n==0 sample -> shared sum is NaN for all readers, forever
right: non-finite values rejected; the shared aggregate stays valid
02weakness catalog

Mapped weaknesses (CWE)

On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.