diff --git a/README.md b/README.md
index 94f5eedddd0a26047b0f87d9ef6d9d6903a2e0ff..406654b8d7f31435f40bdd1ec47444edbc1014d0 100644
--- a/README.md
+++ b/README.md
@@ -53,8 +53,7 @@ npx hardhat run scripts/deploy.js
 # testing on hardhat (forked mainnet, a few blocks ahead of challenge)
 npx hardhat node --fork https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 --fork-block-number 13284495
 
-# challenger is pretending the block 13284491 transition is the transition for 13284469
-# this will conflict at the first step
+# setup and deploy contracts
 mkdir -p /tmp/cannon /tmp/cannon_fault && rm -rf /tmp/cannon/* /tmp/cannon_fault/*
 mipsevm/mipsevm
 npx hardhat run scripts/deploy.js --network hosthat
@@ -63,10 +62,12 @@ cp /tmp/cannon/*.json /tmp/cannon_fault/
 # compute real MIPS checkpoint
 minigeth/go-ethereum 13284469 && mipsevm/mipsevm 13284469
 
-# compute fake MIPS checkpoint (use a symlink to pretend)
+# compute fake MIPS checkpoint
+# challenger is pretending the block 13284491 transition is the transition for 13284469
 BASEDIR=/tmp/cannon_fault minigeth/go-ethereum 13284491 && BASEDIR=/tmp/cannon_fault mipsevm/mipsevm 13284491
 ln -s /tmp/cannon_fault/0_13284491 /tmp/cannon_fault/0_13284469
 
+# start challenge
 BASEDIR=/tmp/cannon_fault BLOCK=13284469 npx hardhat run scripts/challenge.js --network hosthat
 
 # do binary search
@@ -83,6 +84,35 @@ BASEDIR=/tmp/cannon_fault ID=0 BLOCK=13284469 CHALLENGER=1 npx hardhat run scrip
 ID=0 BLOCK=13284469 npx hardhat run scripts/assert.js --network hosthat
 ```
 
+## Alternate challenge with output fault (much slower)
+
+```
+# reset as above
+
+# compute real MIPS checkpoint
+minigeth/go-ethereum 13284491 && mipsevm/mipsevm 13284491
+
+# alternate fake MIPS checkpoint
+BASEDIR=/tmp/cannon_fault minigeth/go-ethereum 13284491 && OUTPUTFAULT=1 BASEDIR=/tmp/cannon_fault mipsevm/mipsevm 13284491
+python3 -c 'f="/tmp/cannon_fault/0_13284491/output";o=b"\xba\xba\xba\xba"+open(f, "rb").read()[4:]; open(f, "wb").write(o)'
+
+# start challenge
+BASEDIR=/tmp/cannon_fault BLOCK=13284491 npx hardhat run scripts/challenge.js --network hosthat
+
+# do binary search
+for i in {1..25}
+do
+OUTPUTFAULT=1 BASEDIR=/tmp/cannon_fault ID=0 BLOCK=13284491 CHALLENGER=1 npx hardhat run scripts/respond.js --network hosthat
+ID=0 BLOCK=13284491 npx hardhat run scripts/respond.js --network hosthat
+done
+
+# assert as challenger (fails)
+OUTPUTFAULT=1 BASEDIR=/tmp/cannon_fault ID=0 BLOCK=13284491 CHALLENGER=1 npx hardhat run scripts/assert.js --network hosthat
+
+# assert as defender (passes)
+ID=0 BLOCK=13284491 npx hardhat run scripts/assert.js --network hosthat
+```
+
 ## State Oracle API
 
 On chain / in MIPS, we have two simple oracles
diff --git a/mipsevm/run_unicorn.go b/mipsevm/run_unicorn.go
index 6175bdbcd87e597b4722de5248537472fe1294f3..77c407922a3936c4ba162d6ac5a06560bcc6ed1e 100644
--- a/mipsevm/run_unicorn.go
+++ b/mipsevm/run_unicorn.go
@@ -73,6 +73,8 @@ func GetHookedUnicorn(root string, ram map[uint32](uint32), callback func(int, u
 	mu, err := uc.NewUnicorn(uc.ARCH_MIPS, uc.MODE_32|uc.MODE_BIG_ENDIAN)
 	check(err)
 
+	_, outputfault := os.LookupEnv("OUTPUTFAULT")
+
 	mu.HookAdd(uc.HOOK_INTR, func(mu uc.Unicorn, intno uint32) {
 		if intno != 17 {
 			log.Fatal("invalid interrupt ", intno, " at step ", steps)
@@ -130,6 +132,10 @@ func GetHookedUnicorn(root string, ram map[uint32](uint32), callback func(int, u
 			rt := value
 			rs := addr64 & 3
 			addr := uint32(addr64 & 0xFFFFFFFC)
+			if outputfault && addr == 0x30000804 {
+				fmt.Printf("injecting output fault over %x\n", rt)
+				rt = 0xbabababa
+			}
 			//fmt.Printf("%X(%d) = %x (at step %d)\n", addr, size, value, steps)
 			if size == 1 {
 				mem := ram[addr]