shared × unstructured — bad data written permanently, and it spreads
Unframed Stream Corruption
Reading a byte stream in fixed chunks with no length contract lets records split and merge — then persist mis-framed.
01the recipe
In the wild
compound ofAsync IO MisuseCWE-130 Length MismatchUnconstrained InputsCWE-400 Resource ExhaustioncompoundCWE-240 Structural Mismatch
example.py
# SMELL: read fixed-size chunks from a stream with no framing contract.
# (async I/O misuse x unconstrained inputs)
async def read_msg(reader):
return await reader.read(1024) # message length is unknown / unbounded
# a 1500-byte message splits across two reads; a 300-byte one merges with the
# next. Records run together and get persisted mis-framed -- corrupt at rest.
# RIGHT: frame the stream; read exactly the declared length.
async def read_msg(reader):
header = await reader.readexactly(4)
n = int.from_bytes(header, "big")
if n > MAX_MSG:
raise ValueError("frame too large")
return await reader.readexactly(n) # exact message boundary, boundedA byte stream has no inherent message boundaries; reading fixed chunks with no length prefix lets one record split and the next merge. The mis-framed bytes are written to the store and read back as garbage -- durable corruption, not a transient glitch.
// observed
unframed: messages split/merge -> mis-framed records persisted corrupt framed: exact length read; each record stored intact
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.