mutated × unstructured — blows up live on input you didn't expect
Shape-Drift AttributeError
An attribute set on only some code paths, read on a path that assumes it always exists.
01the recipe
In the wild
compound ofImproper InitializationCWE-908 Uninit ResourceDuck Typing Without ContractsCWE-20 Input ValidationcompoundCWE-754 Unchecked Condition
example.py
# SMELL: an attribute added only on one path; another path assumes it exists.
# (improper-initialization x duck-typing-without-contracts)
class Job:
def __init__(self): self.status = "new"
def run(job):
if job.status == "retry":
job.result = recompute() # 'result' set ONLY on the retry path
report(job.result) # AttributeError when status != "retry"
# RIGHT: give the shape a contract; every field exists from construction.
class Job:
def __init__(self):
self.status = "new"
self.result = None # always presentBecause result is added on only one branch, every other path reaches for an attribute that was never set. Duck typing hides it until the missing-attribute path runs on real data -- an AttributeError live, not in dev.
// observed
drift: AttributeError: 'Job' object has no attribute 'result' right: field present from construction; absence handled as None
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.