Skip to content
Docs / Attacks and defences

Risks

Attacks considered and how each one is met

For each kind of attacker: the goal, the defences in the way, and the gap that remains. Where the defence is partial, this page says so.


On this page

Observers

Chain analyst

Wants to link deposits, payments and withdrawals. Commitments hide value and owner behind a random blinding; nullifiers cannot be tied to a leaf; every spend has the same two-in, two-out shape with fillers and shuffled outputs; a bundler is the sender. What is left: the privacy set counts the notes in the tree, and at launch it is small, and timing and amount patterns can still link a shield to an unshield. Vary both, leave through fresh addresses and keep ORDEO shielded.

A lying leaf index

Wants you to prove against a fake tree, or wants to find out which notes belong to you. The app passes its rebuilt root to isKnownRoot and stops on a mismatch, and the server sends every leaf to everyone. The most it can do is withhold leaves, which shows up as an error.

Bundlers and spammers

Malicious bundler

Wants to redirect your funds or take more fee. The proof binds recipient, relayer, fee and both ciphertexts through extDataHash; any change fails verification. For a sale, the payout address, minimum, deadline and submitter are inside the bound ciphertext. It can only submit what you built.

Censoring bundler

Refuses or sits on your request. The app tries the next bundler in its list, and you can always submit from your own wallet. A delayed proof whose root has aged out is simply made again.

Gas-draining spammer

Wants the bundler to pay for transactions that revert. Defences: decoding and relayer checks, the fee check, an in-flight set of nullifiers, spent and root checks, a dry run, another eth_call right before signing, a 6M gas cap, per-network bans after reverts, an hourly pause, rate limits, and a surcharge that prices recent losses into the fee. On chain, NotRelayer stops anyone racing the bundler with its own proof. What is left: a user can still spend the same note from their wallet in the same block; that cost is priced in.

Market attacks

Price manipulator against the reference

Wants the bundler to accept too few tokens as a fee, or the harvester to buy at a bad price, by moving the price just before. Both use a median of quotes taken every 5 minutes over 6 hours, ignoring the newest minute, never the quote of the moment. Moving that median means holding the price away from fair for hours, paying for it on every block. The harvester also skips a round when the live price is more than 3% dearer than the reference.

Sandwicher against the harvester

Wants to buy before the harvester and sell into it. Buys are at most 0.02 ETH each, at most 5 per round, with random gaps; rounds start at jittered times; every buy has a minimum of the reference less 1.5%; the price is rechecked before each batch. That is why the harvest is an operated service: an open function anyone could trigger at a chosen moment would be easy to sandwich. Your own buys through the router must carry a minimum too.

Launch sniper

Buys in the first blocks of the curve, when the price is lowest. Ordeo adds no code against this; the curve price rises with each buy, and you set your own minimum output. Shares minted later are priced at the vault’s share price then, so early buyers cannot claim yield that arrived before they shielded. One exception: yield that arrives while no shares exist waits in pendingYield and goes to the first notes shielded after it.

Fees, keys and absent operators

Pons redirecting the creator fee

Only possible after a public 3-day timelock, visible as pendingCreatorFeeRecipient(token). The effect is that new yield stops. Notes and the vault are not affected, and the splitter has no function to give the role away itself.

Team keys

The team address only receives ETH from the splitter. There is no admin key to steal: the deployer has no role after deployment.

Keepers absent

Without a harvester, fees wait in the escrow or the splitter; anyone can still call distribute, and anyone can call buyAndDonate with their own ETH, but the holders’ half sits in the harvester wallet until its key holder spends it. Without a bundler, you submit from your wallet. Notes stay spendable either way.

Protocol limits

Tree exhaustion

The tree holds 16,777,216 leaves. When it is full, every shield and every spend reverts with TreeFull, because each one inserts leaves. There is no second tree or upgrade path. Filling it takes millions of transactions, each paying gas: about a million gas per one-leaf shield, more than four million per two-leaf spend.

Phishing for the activation signature

A fake site requests your activation signature. Because that message follows Sign-In with Ethereum and is bound to ordeo.tech, wallets that check the domain warn you if a different site requests it, and the text itself says to sign only on https://ordeo.tech. With a passphrase, the signature alone is not enough to derive your keys.

Without a passphrase, a leaked signature lets the attacker read and spend all your notes. Sign the activation message only on ordeo.tech.