{-# LANGUAGE OverloadedStrings #-}
module Convex.ThreatModel.TokenForgery (
tokenForgeryAttack,
tokenForgeryAttackWith,
simpleAlwaysSucceedsMintingPolicyV2,
simpleTestAssetName,
) where
import Cardano.Api qualified as C
import Convex.ThreatModel
import Convex.ThreatModel.Cardano.Api (IsPlutusScriptInEra)
import Convex.ThreatModel.TxModifier (addPlutusScriptMint)
import GHC.Exts (fromList)
import PlutusLedgerApi.Test.Examples (alwaysSucceedingNAryFunction)
tokenForgeryAttack
:: (IsPlutusScriptInEra lang)
=> C.PlutusScript lang
-> C.AssetName
-> ThreatModel ()
tokenForgeryAttack :: forall lang.
IsPlutusScriptInEra lang =>
PlutusScript lang -> AssetName -> ThreatModel ()
tokenForgeryAttack = ScriptData -> PlutusScript lang -> AssetName -> ThreatModel ()
forall lang.
IsPlutusScriptInEra lang =>
ScriptData -> PlutusScript lang -> AssetName -> ThreatModel ()
tokenForgeryAttackWith ScriptData
unitRedeemer
where
unitRedeemer :: ScriptData
unitRedeemer = Integer -> [ScriptData] -> ScriptData
C.ScriptDataConstructor Integer
0 []
tokenForgeryAttackWith
:: (IsPlutusScriptInEra lang)
=> C.ScriptData
-> C.PlutusScript lang
-> C.AssetName
-> ThreatModel ()
tokenForgeryAttackWith :: forall lang.
IsPlutusScriptInEra lang =>
ScriptData -> PlutusScript lang -> AssetName -> ThreatModel ()
tokenForgeryAttackWith ScriptData
redeemer PlutusScript lang
mintScript AssetName
assetName = [Char] -> ThreatModel () -> ThreatModel ()
forall a. [Char] -> ThreatModel a -> ThreatModel a
Named [Char]
"Token Forgery Attack" (ThreatModel () -> ThreatModel ())
-> ThreatModel () -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$ do
Output
output <- (Output -> Bool) -> ThreatModel Output
anyOutputSuchThat (AddressAny -> Bool
isKeyAddressAny (AddressAny -> Bool) -> (Output -> AddressAny) -> Output -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Output -> AddressAny
forall t. IsInputOrOutput t => t -> AddressAny
addressOf)
[Char] -> ThreatModel ()
counterexampleTM ([Char] -> ThreatModel ()) -> [Char] -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
[[Char]] -> [Char]
paragraph
[ [Char]
"Testing Token Forgery vulnerability:"
, [Char]
"Attempting to mint additional tokens using the provided minting policy."
, [Char]
"Adding minted tokens to output at " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Doc -> [Char]
forall a. Show a => a -> [Char]
show (AddressAny -> Doc
prettyAddress (AddressAny -> Doc) -> AddressAny -> Doc
forall a b. (a -> b) -> a -> b
$ Output -> AddressAny
forall t. IsInputOrOutput t => t -> AddressAny
addressOf Output
output) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"."
]
[Char] -> ThreatModel ()
counterexampleTM ([Char] -> ThreatModel ()) -> [Char] -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
[[Char]] -> [Char]
paragraph
[ [Char]
"If this validates, the minting policy is too permissive."
, [Char]
"An attacker could forge tokens to:"
, [Char]
"1) Bypass validation token requirements"
, [Char]
"2) Steal assets protected by token checks"
, [Char]
"3) Manipulate protocol state"
]
let scriptHash :: ScriptHash
scriptHash = Script lang -> ScriptHash
forall lang. Script lang -> ScriptHash
C.hashScript (Script lang -> ScriptHash) -> Script lang -> ScriptHash
forall a b. (a -> b) -> a -> b
$ PlutusScriptVersion lang -> PlutusScript lang -> Script lang
forall lang.
IsPlutusScriptLanguage lang =>
PlutusScriptVersion lang -> PlutusScript lang -> Script lang
C.PlutusScript PlutusScriptVersion lang
forall lang.
IsPlutusScriptLanguage lang =>
PlutusScriptVersion lang
plutusScriptVersion PlutusScript lang
mintScript
policyId :: PolicyId
policyId = ScriptHash -> PolicyId
C.PolicyId ScriptHash
scriptHash
mintedValue :: Value
mintedValue = [Item Value] -> Value
forall l. IsList l => [Item l] -> l
fromList [(PolicyId -> AssetName -> AssetId
C.AssetId PolicyId
policyId AssetName
assetName, Quantity
1)]
newValue :: Value
newValue = Output -> Value
forall t. IsInputOrOutput t => t -> Value
valueOf Output
output Value -> Value -> Value
forall a. Semigroup a => a -> a -> a
<> Value
mintedValue
TxModifier -> ThreatModel ()
shouldNotValidate (TxModifier -> ThreatModel ()) -> TxModifier -> ThreatModel ()
forall a b. (a -> b) -> a -> b
$
Output -> Value -> TxModifier
forall t. IsInputOrOutput t => t -> Value -> TxModifier
changeValueOf Output
output Value
newValue
TxModifier -> TxModifier -> TxModifier
forall a. Semigroup a => a -> a -> a
<> PlutusScript lang
-> AssetName -> Quantity -> ScriptData -> TxModifier
forall lang.
IsPlutusScriptInEra lang =>
PlutusScript lang
-> AssetName -> Quantity -> ScriptData -> TxModifier
addPlutusScriptMint PlutusScript lang
mintScript AssetName
assetName (Integer -> Quantity
C.Quantity Integer
1) ScriptData
redeemer
simpleAlwaysSucceedsMintingPolicyV2 :: C.PlutusScript C.PlutusScriptV2
simpleAlwaysSucceedsMintingPolicyV2 :: PlutusScript PlutusScriptV2
simpleAlwaysSucceedsMintingPolicyV2 =
ShortByteString -> PlutusScript PlutusScriptV2
forall lang. ShortByteString -> PlutusScript lang
C.PlutusScriptSerialised (ShortByteString -> PlutusScript PlutusScriptV2)
-> ShortByteString -> PlutusScript PlutusScriptV2
forall a b. (a -> b) -> a -> b
$
Natural -> ShortByteString
alwaysSucceedingNAryFunction Natural
2
simpleTestAssetName :: C.AssetName
simpleTestAssetName :: AssetName
simpleTestAssetName = ByteString -> AssetName
C.UnsafeAssetName ByteString
""