Reproduced Exploit

Myriad CLOB — free YES tokens when cross-market `priceSum > ONE`

1. Cross-market match requires only priceSum >= ONE, not equality. 2. Maker notionals sum with round-down; taker pays max(0, fill - notionalSoFar). 3. When priceSum > ONE, makers overpay and taker notional becomes 0. 4. Taker still receives full fillAmount YES tokens.

Mar 2026Otheruntagged3 min read

Chain

Other

Category

untagged

Date

Mar 2026

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 65419-myriadctfexchangematchcrossmarketorders-allows-taker-to-rece. Standalone Foundry PoC and full write-up: 65419-myriadctfexchangematchcrossmarketorders-allows-taker-to-rece_exp in the evm-hack-registry mirror.


Vulnerability classes: wrong-condition · direct-drain · locked-funds

Reproduction: self-contained Foundry PoC with only forge-std. Full trace: output.txt. PoC: test/65419-myriadctfexchangematchcrossmarketorders-allows-taker-to-rece_exp.sol.

AuditVault taxonomy: lang/solidity · sector/dex · sector/lending · platform/cyfrin · has/github · has/poc · severity/high · impact/loss-of-funds/direct-drain · impact/loss-of-funds/locked-funds · genome: wrong-condition · direct-drain · locked-funds


Key info#

ImpactHIGH — taker receives YES for free; surplus collateral stuck forever
ProtocolMyriad / Polkamarkets CLOB
Vulnerable codeMyriadCTFExchange.matchCrossMarketOrders
Bug classpriceSum >= ONE allows overpay; taker notional clamped to 0
FindingCyfrin Myriad CLOB v2.0, 2026-03-13 · #65419 · Kiki
ReportCyfrin report
SourceAuditVault
StatusFixed in c820bcf / d4300b9
Compiler^0.8.24 (PoC)

TL;DR#

  1. Cross-market match requires only priceSum >= ONE, not equality.
  2. Maker notionals sum with round-down; taker pays max(0, fill - notionalSoFar).
  3. When priceSum > ONE, makers overpay and taker notional becomes 0.
  4. Taker still receives full fillAmount YES tokens.
  5. Surplus collateral remains on the exchange with no withdraw path.

The vulnerable code#

SOLIDITY
require(priceSum >= ONE, "price sum < 1"); // @> VULN
notional = notionalSoFar >= fillAmount ? 0 : fillAmount - notionalSoFar; // @> VULN

Fix: each buyer pays their price; route surplus to treasury/feeModule; prefer priceSum == ONE.


Root cause#

Remainder-based taker notional assumes maker notionals never exceed fill. That holds for priceSum == ONE (modulo dust) but fails when operators pass a higher sum.


Preconditions#

  • Operator (or attacker with operator role) matches orders with priceSum > ONE.
  • Makers have approved collateral.

Attack walkthrough#

  1. Build three buy orders priced 0.60 + 0.60 + 0.10 = 1.30.
  2. Match with fillAmount = 100.
  3. Makers pay 60 + 60 = 120; taker pays 0.
  4. All three receive 100 YES; 20 collateral stuck on exchange.

Diagrams#

flowchart LR PS["priceSum 1.30 > ONE"] --> M["makers pay 120"] M --> T["taker notional 0"] T --> Y["taker gets 100 YES free"] M --> S["20 collateral stuck"]

Impact#

Taker steals value from overpaying makers; surplus is locked until an upgrade/recovery path.


Sources#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.