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

Stored / Second-Order Injection

Unvalidated input is persisted once, then trusted every time it is read back out.

01the recipe

In the wild

example.py
# SMELL: store unvalidated input, then trust it on the way back out.
# (file / network access x lack of input validation)
db.execute("INSERT INTO notes(body) VALUES (?)", [body])   # raw user HTML stored
...
page += row["body"]            # later rendered to every viewer -> stored XSS
# or: db.execute("... WHERE name = '" + row["name"] + "'")  # second-order SQLi

# RIGHT: validate on the way in, encode on the way out, parameterize always.
db.execute("INSERT INTO notes(body) VALUES (?)", [clean(body)])
page += escape_html(row["body"])
The poison is written once and read forever: unvalidated input persisted to a shared store comes back as executable markup or SQL. The damage is durable and reaches every later reader, not just the attacker.
// observed
stored:   one bad row scripts every viewer / re-injects on read
sanitized: cleaned in, encoded out -- inert at rest
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.