| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Convex.ThreatModel.InvalidDatumIndex
Description
Threat model for detecting Invalid Datum Index vulnerabilities.
An Invalid Datum Index Attack mutates the constructor index of a Constr datum
on a script output to a value outside the expected range. If a validator's
FromData parser uses a wildcard or permissive otherwise branch when
deserialising the constructor index, an attacker can supply an invalid index
that still matches a catch-all and is interpreted as a legitimate state.
Consequences ==
- State confusion: If the out-of-range index accidentally matches a
catch-all or default branch in
unsafeFromBuiltinData, the validator may interpret the datum as a valid (but semantically wrong) state, allowing unintended transitions or fund extraction. - Permanent fund locking: If the invalid index triggers a script error at spend time, any UTxO locked with that corrupted datum becomes permanently unspendable.
Root Cause ==
Validators that use unsafeFromBuiltinData or manually pattern-match on
constructor indices without explicitly rejecting unexpected values are at risk.
For example:
case index of 0 -> Pinged 1 -> Ponged _ -> Stopped -- catch-all silently accepts ANY other index!
This means Constr 99 [] would decode as Stopped, bypassing any guard that
should have rejected it.
Mitigation ==
A secure validator should explicitly enumerate all valid indices and call
P.traceError (or equivalent) for any unexpected constructor index:
case index of 0 -> Pinged 1 -> Ponged 2 -> Stopped _ -> P.traceError "PingPongState: invalid index"
This threat model tests whether a script output with an inline datum still
validates when the Constr index is replaced with an out-of-range value.
If it does, the validator has an Invalid Datum Index vulnerability.
Synopsis
Documentation
invalidDatumIndexAttack :: ThreatModel () Source #
Default invalid-datum-index attack. The replacement constructor index is drawn per transaction from a curated range starting at 3 (above the typical 0, 1, 2 indices of most Plutus sum types), so QuickCheck explores the parameter space without accidentally hitting a valid index.
invalidDatumIndexAttackWith :: Integer -> ThreatModel () Source #
Invalid-datum-index attack with a fixed constructor index. Keep using this for deterministic regression tests and golden seeds.
invalidDatumIndexAttackWithGen :: Gen Integer -> ThreatModel () Source #
Invalid-datum-index attack parameterised by a generator for the replacement constructor index. This is the primitive the other two forms delegate to.
replaceConstrIndex :: Integer -> ScriptData -> ScriptData Source #
Replace the constructor index of a ScriptDataConstructor with newIdx,
preserving all fields.
For other ScriptData variants (Map, List, Number, Bytes) the value
is returned unchanged and the precondition filter above will have already
excluded non-Constr datums.