mutated × unstructured — blows up live on input you didn't expect
Aliased-Default Type Confusion
A function's mutable default is shared across calls; one caller seeds it with a wrong-typed value, and a later caller crashes operating on it.
01the recipe
In the wild
compound ofAliasing & Mutable DefaultsCWE-471 MAID (Modification of Immutable Data)Type Errors in Dynamic LanguagesCWE-704 Bad CastcompoundCWE-843 Type Confusion
example.py
# SMELL: a shared mutable default accumulates state across calls.
# (aliasing mutable defaults x type errors)
def collect(item, into=[]): # one list, shared by every call
into.append(item)
return sum(into) # crashes once a non-number slips in
collect(1); collect(2) # fine
collect("x") # TypeError on the NEXT caller's sum(into)
# RIGHT: a fresh container per call; the type stays local and predictable.
def collect(item, into=None):
into = [] if into is None else into
into.append(item)
return sum(into)The default list is created once and aliased by every call, so values -- and their types -- leak between callers. One caller appending a string poisons the shared default; a later caller's sum() hits incompatible types, a crash with no obvious owner. Default to None and build a fresh container inside.
// observed
shared: TypeError in a caller that never touched a string right: each call owns its list; types stay local
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.