Doji docs
Security

Try to break it

Twelve attacks you can run against the live contracts from the site, and what each one should hit.

Try to break it runs twelve attacks against the live contracts on Mezo testnet and shows exactly how the contracts refuse each one. Nothing is sent: every attack is a simulated call, so nothing is signed and no gas is spent.

How the page works

  • A switch at the top picks who attacks. "Run as a stranger" simulates from a fixed address that holds no role in Doji. "Run from my wallet" simulates from your connected wallet, which is never asked to sign.
  • The targets are read live, never hard-coded: the example loan from the deployment record, an open auction if there is one, the first open offer, the next Thursday and the earliest Thursday with an open offer.
  • Each card shows the attack, one line on what it tries, the exact call, the rule it tests (linked to the threat model) and a "Run it" button. "Run all" runs every card in turn.
  • The result reads "Refused:" with the contract's error and a plain explanation, and the block the simulation ran on. If a call would succeed, the card says "This would go through" and why. For example, if your wallet is the demo position's own borrower and it has no loan, attack 1 goes through: that is the rule working for its owner, not a hole.

The twelve attacks

#AttackCallExpected refusalRules
1Take someone else's BitcoinLoanManager.withdrawCollateral(example loan)NotBorrowerC4
2Borrow against someone else's positionLoanManager.borrow(example loan, earliest Thursday, [first offer], [10 MUSD], 5000)NotBorrowerC4
3Vote with someone else's positionLoanManager.vote(example loan, [first PoolsVoter pool], [10000])NotBorrowerC4, C5
4Start an auction on a healthy loanLoanManager.startAuction(example loan)NotLiquidatable while it is safe and on timeC11
5Settle a loan that isn't in auctionLoanManager.settle(example loan)NoAuctionC12
6Buy a position for almost nothingLoanManager.purchase(open auction, 1 MUSD, now + 600)PriceAboveMax, or NoAuction on the example loan when no auction is openC11, C29
7Fill an offer without a loanCreditMarkets.fill(earliest Thursday, [first offer], [10 MUSD], 5000, caller)NotLoanManagerC27
8Credit a market with nothingCreditMarkets.credit(earliest Thursday, 1 MUSD, true)NotLoanManagerC14, C27
9Cancel someone else's offerCreditMarkets.cancelOffer(first offer)NotMakerC16
10Cash out before the dateCreditMarkets.withdrawCollected(next Thursday, 0)NotMaturedC15
11Take users' tokens as the ownerLoanManager.rescueToken(MUSD, caller, 1)OwnableUnauthorizedAccountC19, C28
12Give up ownershipLoanManager.renounceOwnership()RenounceDisabledC19

The example loan is veBTC #389. If the example loan is ever overdue or unsafe, attack 4 would go through, and the page says so: starting the auction of a loan that deserves one is a call anyone is meant to make.

From the command line

The same twelve attacks run read-only, with no key, from packages/web:

npx tsx scripts/check-attacks.ts

It prints each attack with the contract's refusal and the block, then how many were refused with the expected error.

If you find a way through, open an issue on GitHub.