Skip to content

test(twap-monitor): cover a fully fabricated ConditionalOrderCreated log - #674

Open
lgahdl wants to merge 1 commit into
nullislabs:mainfrom
bleu:investigate/cow-1215-fabricated-events
Open

test(twap-monitor): cover a fully fabricated ConditionalOrderCreated log#674
lgahdl wants to merge 1 commit into
nullislabs:mainfrom
bleu:investigate/cow-1215-fabricated-events

Conversation

@lgahdl

@lgahdl lgahdl commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Reproduction for #673.

decode_conditional_order_created only checks topic-0 — already enforced by the engine's address+topic-0 chain-log filter — and never checks that the log corresponds to a real chain inclusion. The same is true on the poll side: poll_one/decode_return blindly ABI-decode whatever the eth_call response contains. A malicious/compromised RPC provider controls both the log delivery and the eth_call response, so it can drive the entire pipeline — index a watch, report it poll-ready, trigger a real submission attempt — purely from fabricated data, with nothing in the module ever cross-checking the RPC's honesty.

What this adds

One test, fabricated_create_log_drives_a_real_submit_attempt_with_no_local_cross_check, proving the chain end to end:

  1. A ConditionalOrderCreated log for an invented (owner, ConditionalOrderParams) pair, with no on-chain backing whatsoever, is fed to on_chain_logs → confirmed the watch is persisted unconditionally.
  2. A fabricated "ready" eth_call response (arbitrary GPv2OrderData + a signature that verifies nothing) is programmed for the corresponding poll.
  3. on_block is dispatched → confirmed a real submit attempt reaches the venue (venue.submit_count() == 1), with no local check anywhere in on_chain_logs, the poll path, or submit_ready refusing it.

No production code changes — this is reproduction/regression coverage for #673, which has the full writeup and a proportionate suggested improvement (documenting the trust boundary explicitly, plus a venue-denial-rate signal as an operational indicator of a compromised RPC — full cryptographic verification is out of proportion for a keeper module).

Testing

cargo test --manifest-path modules/twap-monitor/Cargo.toml: 26/26 pass (25 pre-existing + the new one), no regressions.

AI Assistance: Claude Code was used for the investigation and this test, as part of a follow-up TWAP-flow red-team pass.

decode_conditional_order_created only checks topic-0 (already enforced
by the engine's address+topic-0 filter); nothing checks that the log
corresponds to a real chain inclusion. The same is true on the poll
side: poll_one/decode_return blindly ABI-decode whatever the eth_call
response contains. A malicious/compromised RPC controls both the log
delivery and the eth_call response, so it can drive the entire
pipeline - index a watch, report it poll-ready, trigger a real
submission attempt - purely from fabricated data.

This test proves the chain end to end: a ConditionalOrderCreated log
for an invented (owner, ConditionalOrderParams) pair with no on-chain
backing is persisted as a watch unconditionally, and a fabricated
"ready" eth_call response then drives a real submit attempt to the
venue, with no local check anywhere in on_chain_logs, the poll path, or
submit_ready refusing it on the RPC's say-so alone.

No production code changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant