Maren
GitHub
Security

Audits

Three adversarial self-audits — two of Maren's own contracts, one against Mezo's live bytecode — what they found, and what a paid audit gates.

Before anything went out, three adversarial audits ran: two against Maren's own contracts, and one against Mezo's live bytecode. They found real bugs, which is the point. Each report names what was attacked and held, not only what broke. The reports live in docs/audit/ in the repository, which is private during the grant review and opens with the paid audit.

These are pre-audit hardening passes by the author's own tooling, not a substitute for a paid third-party audit. A paid audit gates mainnet. No Maren contract reaches mainnet before an independent audit of MarenVault, MarenEarn and MarenRelayHub — Earn holds user principal in a pool that can lose it, which puts it in scope — with findings and remediations published.

The fixes below are fixed in source, not on chain. The contract deployed to matsnet (0x46252B00…645b) predates the redemption splitter: reconcileRedemption, settleRedemption, collateralOf and redemptionShortfall are all absent from its dispatch table, verifiable with cast code. Until that build is replaced, a redemption against the pooled trove would go unreconciled. Only testnet BTC is exposed. Redeploying is a prerequisite for any mainnet claim.

The three audits

Contracts

MarenVault and the redemption splitter. A permissionless fund-drain (H-1) and a bounded High (H-2), both found and fixed in source; both fixes are still pending redeployment to matsnet.

Mezo conformance

Every selector Maren calls checked against the deployed bytecode. Two bugs found and fixed.

Meta-transaction path

The relayer, forwarder, and web relay client. A budget-halt denial of service fixed.

Contracts audit

Scope was MarenVault and the redemption splitter, measured against Mezo's own source (MEZO-GROUND-TRUTH.md) and the SDK's divergence records.

H-1 (FIXED IN SOURCE, NOT YET DEPLOYED): a shortfall re-read as a phantom redemption

A recognised redemption shortfall was re-read on the next sync as a fresh redemption and charged pro rata to every solvent debtor, repeatedly, with no relief attached, until the shortfall was fully socialised. Both entrypoints are permissionless and need no price, so any passer-by could grind the loop; the measured Foundry reproduction drained 0.03364 BTC from a solvent debtor (about $2,122 at the test fixture's $63,072 BTC price — the dollar figure moves with BTC, the 0.03364 does not). Fixed by routing the detector and preview through one function that subtracts the recorded shortfall before comparing books with trove. Two regression tests, both proven to fail against the pre-fix contract.

H-2 (FIXED IN SOURCE, NOT YET DEPLOYED): relief the reserve over-covers is absorbed by the protocol

When a redemption cancels more trove debt than the pool's users owe, which needs a non-zero MUSD reserve, users were charged collateral for relief that landed in the reserve where no user has a direct claim. The loss was bounded by reserveMUSD at the instant of redemption. Fixed by having the protocol's own position absorb that excess instead of splitting it across users, so each user loses collateral worth exactly the debt they stopped owing. The pinning test was inverted to assert users are made whole, and proven to fail against the pre-fix code. Residual for the paid audit: if the protocol's own position is exhausted, the remainder falls to the shortfall path. See Redemptions.

Lower-severity items

Several Medium and Info items are documented (an admin-path gap on a non-active trove, an unbounded per-share growth as debt shares shrink) and two Info items fixed with guards and pinned tests. Each carries a reproduction or an argument.

The audit also records what was attacked and held, including the interest-first ordering question the ground-truth file headlines, verified correct under a proof rather than assumed.

Mezo conformance audit

The question: does Maren integrate with Mezo and MUSD correctly, against the contracts actually deployed rather than the documentation? Audited 19 August 2026 against both networks, working at the dispatch table: for each proxy the EIP-1967 implementation slot was read, the implementation bytecode fetched, and the 4-byte selector of every function Maren declares searched for inside it.

VerdictCountWhere
PASS64Selectors, divergences, doc discrepancies, hints, oracle, precompiles
DRIFTED6Recovery Mode, a payment event topic, an unread staleness flag, three byte counts
UNPROVEN3Refinance-fee arithmetic, circulating-vs-backed ratio, MEZO token precompile

Every one of the 44 function selectors Maren declares exists on the deployed contract with the argument types Maren encodes, on both networks. Two bugs were found and fixed:

Recovery Mode blocks more than recorded

Read out of the deployed BorrowerOperations bytecode: in Recovery Mode, borrow and collateral withdrawal are closed outright and revert with a bare Error(string). Maren had no defence at any layer. Fixed, with a test.

A payment event with a phantom parameter

A PaidToHandle event signature hashed to a topic the chain never emits, silently dropping every handle payment from Activity. Fixed, with a test.

Negative controls are part of what makes this pass stronger than a getter check: every Liquity-shaped variant carrying _maxFeePercentage was searched for too, and confirmed absent on both networks. A claim that a parameter does not exist is only worth something if the method could have found it.

Meta-transaction audit

Scope was the forwarder and relay hub contracts, the whole relayer service, and the web relay client, read against ground truth with live cast calls where a claim could be settled on-chain.

High (FIXED): a signer-chosen gas ceiling latches the daily budget halt

The day-long budget halt latched on committed spend debited with request.gas, a ceiling the signer picks, and reconciliation never re-read the latch. One request signing 1,000,000 gas against a budget sized for it took the relayer offline for the rest of the day, though the transaction settled at 120,000 gas, and it costs nothing to do on purpose. Fixed: the halt is lifted when reconciliation shows committed spend back under the limit, with three regression tests.

Medium/Low fixed items

Calldata gas moved inside the signed reservation; a failed reservation now refunded; the hub validates before calling an arbitrary address; the web client no longer believes a 202 on its hash alone; the relayer URL must not be plaintext.

Documented items

executeWithFee has no fee-token allowlist (needs a contract redeploy); the free tier is Sybilable and the daily BTC cap is the real bound; health endpoints disclose posture. Each is documented with its bound.

The relayer's four adversarial rounds were structured attacks on Maren's own design. Round two found a budget race allowing 52x overspend; round three found the fix created a denial-of-service path; round four found the CI had never actually exercised the relayer's code. Each finding is fixed and regression-tested.

What holds every fix honest

Every fix was verified to fail against the unfixed code, by reverting the change and re-running the suite. That is the discipline behind the whole product: a claim is only as good as the test that would break if it were false.