diff --git a/op-challenger/game/keccak/scheduler.go b/op-challenger/game/keccak/scheduler.go
index f25e198cbe3fd20258987a71b2b8b949ee0cf3f7..7a9b5a838cd30567db2af7a048f70cea29ed86cc 100644
--- a/op-challenger/game/keccak/scheduler.go
+++ b/op-challenger/game/keccak/scheduler.go
@@ -9,19 +9,25 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 )
 
+type Verifier interface {
+	Verify(ctx context.Context, oracle types.LargePreimageOracle, preimage types.LargePreimageMetaData)
+}
+
 type LargePreimageScheduler struct {
-	log     log.Logger
-	ch      chan common.Hash
-	oracles []types.LargePreimageOracle
-	cancel  func()
-	wg      sync.WaitGroup
+	log      log.Logger
+	ch       chan common.Hash
+	oracles  []types.LargePreimageOracle
+	verifier Verifier
+	cancel   func()
+	wg       sync.WaitGroup
 }
 
-func NewLargePreimageScheduler(logger log.Logger, oracles []types.LargePreimageOracle) *LargePreimageScheduler {
+func NewLargePreimageScheduler(logger log.Logger, oracles []types.LargePreimageOracle, verifier Verifier) *LargePreimageScheduler {
 	return &LargePreimageScheduler{
-		log:     logger,
-		ch:      make(chan common.Hash, 1),
-		oracles: oracles,
+		log:      logger,
+		ch:       make(chan common.Hash, 1),
+		oracles:  oracles,
+		verifier: verifier,
 	}
 }
 
@@ -71,6 +77,11 @@ func (s *LargePreimageScheduler) verifyPreimages(ctx context.Context, blockHash
 }
 
 func (s *LargePreimageScheduler) verifyOraclePreimages(ctx context.Context, oracle types.LargePreimageOracle, blockHash common.Hash) error {
-	_, err := oracle.GetActivePreimages(ctx, blockHash)
+	preimages, err := oracle.GetActivePreimages(ctx, blockHash)
+	for _, preimage := range preimages {
+		if preimage.ShouldVerify() {
+			s.verifier.Verify(ctx, oracle, preimage)
+		}
+	}
 	return err
 }
diff --git a/op-challenger/game/keccak/scheduler_test.go b/op-challenger/game/keccak/scheduler_test.go
index cdbb0c385f0b30cb55c7d60fcba53e8bdba2cfc2..23d39120092282359c238e469b422fccabd0dc13 100644
--- a/op-challenger/game/keccak/scheduler_test.go
+++ b/op-challenger/game/keccak/scheduler_test.go
@@ -2,6 +2,7 @@ package keccak
 
 import (
 	"context"
+	"math/big"
 	"sync"
 	"testing"
 	"time"
@@ -16,8 +17,32 @@ import (
 func TestScheduleNextCheck(t *testing.T) {
 	ctx := context.Background()
 	logger := testlog.Logger(t, log.LvlInfo)
-	oracle := &stubOracle{}
-	scheduler := NewLargePreimageScheduler(logger, []types.LargePreimageOracle{oracle})
+	preimage1 := types.LargePreimageMetaData{ // Incomplete so won't be verified
+		LargePreimageIdent: types.LargePreimageIdent{
+			Claimant: common.Address{0xab},
+			UUID:     big.NewInt(111),
+		},
+	}
+	preimage2 := types.LargePreimageMetaData{ // Already countered so won't be verified
+		LargePreimageIdent: types.LargePreimageIdent{
+			Claimant: common.Address{0xab},
+			UUID:     big.NewInt(222),
+		},
+		Timestamp: 1234,
+		Countered: true,
+	}
+	preimage3 := types.LargePreimageMetaData{
+		LargePreimageIdent: types.LargePreimageIdent{
+			Claimant: common.Address{0xdd},
+			UUID:     big.NewInt(333),
+		},
+		Timestamp: 1234,
+	}
+	oracle := &stubOracle{
+		images: []types.LargePreimageMetaData{preimage1, preimage2, preimage3},
+	}
+	verifier := &stubVerifier{}
+	scheduler := NewLargePreimageScheduler(logger, []types.LargePreimageOracle{oracle}, verifier)
 	scheduler.Start(ctx)
 	defer scheduler.Close()
 	err := scheduler.Schedule(common.Hash{0xaa}, 3)
@@ -25,12 +50,18 @@ func TestScheduleNextCheck(t *testing.T) {
 	require.Eventually(t, func() bool {
 		return oracle.GetPreimagesCount() == 1
 	}, 10*time.Second, 10*time.Millisecond)
+	require.Eventually(t, func() bool {
+		verified := verifier.Verified()
+		t.Logf("Verified preimages: %v", verified)
+		return len(verified) == 1 && verified[0] == preimage3
+	}, 10*time.Second, 10*time.Millisecond, "Did not verify preimage")
 }
 
 type stubOracle struct {
 	m                 sync.Mutex
 	addr              common.Address
 	getPreimagesCount int
+	images            []types.LargePreimageMetaData
 }
 
 func (s *stubOracle) Addr() common.Address {
@@ -41,7 +72,7 @@ func (s *stubOracle) GetActivePreimages(_ context.Context, _ common.Hash) ([]typ
 	s.m.Lock()
 	defer s.m.Unlock()
 	s.getPreimagesCount++
-	return nil, nil
+	return s.images, nil
 }
 
 func (s *stubOracle) GetPreimagesCount() int {
@@ -49,3 +80,22 @@ func (s *stubOracle) GetPreimagesCount() int {
 	defer s.m.Unlock()
 	return s.getPreimagesCount
 }
+
+type stubVerifier struct {
+	m        sync.Mutex
+	verified []types.LargePreimageMetaData
+}
+
+func (s *stubVerifier) Verify(_ context.Context, _ types.LargePreimageOracle, image types.LargePreimageMetaData) {
+	s.m.Lock()
+	defer s.m.Unlock()
+	s.verified = append(s.verified, image)
+}
+
+func (s *stubVerifier) Verified() []types.LargePreimageMetaData {
+	s.m.Lock()
+	defer s.m.Unlock()
+	v := make([]types.LargePreimageMetaData, len(s.verified))
+	copy(v, s.verified)
+	return v
+}
diff --git a/op-challenger/game/keccak/verifier.go b/op-challenger/game/keccak/verifier.go
new file mode 100644
index 0000000000000000000000000000000000000000..08a21aef7c6b9fdb3434dbc02125e9ae55217a85
--- /dev/null
+++ b/op-challenger/game/keccak/verifier.go
@@ -0,0 +1,22 @@
+package keccak
+
+import (
+	"context"
+
+	"github.com/ethereum-optimism/optimism/op-challenger/game/types"
+	"github.com/ethereum/go-ethereum/log"
+)
+
+type PreimageVerifier struct {
+	log log.Logger
+}
+
+func NewPreimageVerifier(logger log.Logger) *PreimageVerifier {
+	return &PreimageVerifier{
+		log: logger,
+	}
+}
+
+func (v *PreimageVerifier) Verify(ctx context.Context, oracle types.LargePreimageOracle, preimage types.LargePreimageMetaData) {
+	// No verification currently performed.
+}
diff --git a/op-challenger/game/service.go b/op-challenger/game/service.go
index 62617248391740e6dbf0a6ed5b46abf3fb2ca690..9dec7f841b5fe67f10d21631e5fa59db0b33d53f 100644
--- a/op-challenger/game/service.go
+++ b/op-challenger/game/service.go
@@ -225,7 +225,8 @@ func (s *Service) initScheduler(cfg *config.Config) error {
 }
 
 func (s *Service) initLargePreimages() error {
-	s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.registry.Oracles())
+	verifier := keccak.NewPreimageVerifier(s.logger)
+	s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.registry.Oracles(), verifier)
 	return nil
 }
 
diff --git a/op-challenger/game/types/types.go b/op-challenger/game/types/types.go
index e3c03cf5bdccad45ce58eb4d2d224b31b445de21..3d3b631978caf38f9dba430f08b05f9b70216463 100644
--- a/op-challenger/game/types/types.go
+++ b/op-challenger/game/types/types.go
@@ -62,6 +62,12 @@ type LargePreimageMetaData struct {
 	Countered       bool
 }
 
+// ShouldVerify returns true if the preimage upload is complete and has not yet been countered.
+// Note that the challenge period for the preimage may have expired but the image not yet been finalized.
+func (m LargePreimageMetaData) ShouldVerify() bool {
+	return m.Timestamp > 0 && !m.Countered
+}
+
 type LargePreimageOracle interface {
 	Addr() common.Address
 	GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]LargePreimageMetaData, error)