{-# LANGUAGE OverloadedStrings #-}
module Convex.ThreatModel.DuplicateListEntry (
duplicateListEntryAttack,
duplicateFirstEntry,
) where
import Convex.ThreatModel
duplicateListEntryAttack :: ThreatModel ()
duplicateListEntryAttack :: ThreatModel ()
duplicateListEntryAttack = String -> ThreatModel () -> ThreatModel ()
forall a. String -> ThreatModel a -> ThreatModel a
Named String
"Duplicate List Entry Attack" (ThreatModel () -> ThreatModel ())
-> ThreatModel () -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$ do
(Output
target, ScriptData
originalDatum) <- ThreatModel (Output, ScriptData)
anyGuardedOutputWithInlineDatum
let modifiedDatum :: ScriptData
modifiedDatum = ScriptData -> ScriptData
duplicateFirstEntry ScriptData
originalDatum
ThreatModel () -> ThreatModel ()
forall a. ThreatModel a -> ThreatModel a
threatPrecondition (ThreatModel () -> ThreatModel ())
-> ThreatModel () -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$ Bool -> ThreatModel ()
ensure (ScriptData
modifiedDatum ScriptData -> ScriptData -> Bool
forall a. Eq a => a -> a -> Bool
/= ScriptData
originalDatum)
String -> ThreatModel ()
counterexampleTM (String -> ThreatModel ()) -> String -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
[String] -> String
paragraph
[ String
"The transaction contains a script output at index"
, TxIx -> String
forall a. Show a => a -> String
show (Output -> TxIx
outputIx Output
target)
, String
"with an inline datum containing list fields."
]
String -> ThreatModel ()
counterexampleTM (String -> ThreatModel ()) -> String -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
[String] -> String
paragraph
[ String
"Testing if duplicating the first entry in list fields"
, String
"still passes validation."
]
String -> ThreatModel ()
counterexampleTM (String -> ThreatModel ()) -> String -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
[String] -> String
paragraph
[ String
"If this validates, the script doesn't enforce list uniqueness."
, String
"An attacker could exploit this to:"
, String
"1) Bypass multisig requirements by signing once and duplicating"
, String
"2) Manipulate votes by duplicating voter entries"
, String
"3) Claim multiple rewards by duplicating beneficiary entries"
]
TxModifier -> ThreatModel ()
shouldNotValidate (TxModifier -> ThreatModel ()) -> TxModifier -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$ Output -> Datum -> TxModifier
forall t. IsInputOrOutput t => t -> Datum -> TxModifier
changeDatumOf Output
target (ScriptData -> Datum
toInlineDatum ScriptData
modifiedDatum)
duplicateFirstEntry :: ScriptData -> ScriptData
duplicateFirstEntry :: ScriptData -> ScriptData
duplicateFirstEntry (ScriptDataConstructor Integer
idx [ScriptData]
fields) =
Integer -> [ScriptData] -> ScriptData
ScriptDataConstructor Integer
idx ((ScriptData -> ScriptData) -> [ScriptData] -> [ScriptData]
forall a b. (a -> b) -> [a] -> [b]
map ScriptData -> ScriptData
duplicateFirstEntry [ScriptData]
fields)
duplicateFirstEntry (ScriptDataList (ScriptData
x : [ScriptData]
xs)) =
[ScriptData] -> ScriptData
ScriptDataList (ScriptData
x ScriptData -> [ScriptData] -> [ScriptData]
forall a. a -> [a] -> [a]
: ScriptData
x ScriptData -> [ScriptData] -> [ScriptData]
forall a. a -> [a] -> [a]
: [ScriptData]
xs)
duplicateFirstEntry (ScriptDataList []) =
[ScriptData] -> ScriptData
ScriptDataList []
duplicateFirstEntry (ScriptDataMap [(ScriptData, ScriptData)]
entries) =
[(ScriptData, ScriptData)] -> ScriptData
ScriptDataMap [(ScriptData -> ScriptData
duplicateFirstEntry ScriptData
k, ScriptData -> ScriptData
duplicateFirstEntry ScriptData
v) | (ScriptData
k, ScriptData
v) <- [(ScriptData, ScriptData)]
entries]
duplicateFirstEntry ScriptData
x = ScriptData
x