Aeva Info
An asset-native L1 for programmable ownership, financial rights, and settlement.
TrustNet Score
The TrustNet Score evaluates crypto projects based on audit results, security, KYC verification, and social media presence. This score offers a quick, transparent view of a project's credibility, helping users make informed decisions in the Web3 space.
Real-Time Threat Detection
Real-time threat detection, powered by Cyvers.io,
is currently not
activated
for this project.
This advanced feature provides continuous monitoring and instant alerts to safeguard your assets from potential security threats. Real-time detection enhances your project's security by proactively identifying and mitigating risks.
For more information, click here.
Security Assessments
Summary and Final Words
No crucial issues found
The contract does not contain issues of high or medium criticality. This means that no known vulnerabilities were found in the source code.
Scope of Work
This audit encompasses the evaluation of the files listed below, each verified with a SHA-1 Hash. The team referenced above has provided the necessary files for assessment.
The auditing process consists of the following systematic steps:
- Specification Review: Analyze the provided specifications, source code, and instructions to fully understand the smart contract's size, scope, and functionality.
- Manual Code Examination: Conduct a thorough line-by-line review of the source code to identify potential vulnerabilities and areas for improvement.
- Specification Alignment: Ensure that the code accurately implements the provided specifications and intended functionalities.
- Test Coverage Assessment: Evaluate the extent and effectiveness of test cases in covering the codebase, identifying any gaps in testing.
- Symbolic Execution: Analyze the smart contract to determine how various inputs affect execution paths, identifying potential edge cases and vulnerabilities.
- Best Practices Evaluation: Assess the smart contracts against established industry and academic best practices to enhance efficiency, maintainability, and security.
- Actionable Recommendations: Provide detailed, specific, and actionable steps to secure and optimize the smart contracts.
A file with a different Hash has been intentionally or otherwise modified after the security review. A different Hash may indicate a changed condition or potential vulnerability that was not within the scope of this review.
Final Words
The following provides a concise summary of the audit report, accompanied by insightful comments from the auditor. This overview captures the key findings and observations, offering valuable context and clarity.
Smart Contract Analysis Statement
Contract Analysis
The Aeva bridge connects aeva-1 with Robinhood Chain over Hyperlane. On aeva-1 a Cosmos SDK module written in Go (x/bridge) runs two routes: native AEVA is locked in and released from a genesis-funded escrow and is never minted, and USDG arrives as a synthetic aeUSD that is minted and burned. Each route has a rolling 24 hour cap per direction and a pause. On Robinhood Chain two stock Hyperlane collateral routers hold the bridged tokens behind AevaBridgeGuard, a Solidity contract that is both routers' post-dispatch hook and security module and applies a pause, recipient rules and per-transfer and daily limits before the validators' 2-of-2 multisig decides. Since 2026-10-25 the Safe that owns the routers and the guard is itself behind AevaSafeGuard, a transaction guard that refuses the routers' rebalance and fee paths and delays every loosening by 24 hours. This re-audit verified the remediation released in aevad v1.1.2 and v1.1.4 and the two new contracts, all live. The critical replay is fixed: aeva-1 accepts deliveries only from the bridge's mailbox and refuses a signed mailbox creation. The rolling window now keeps one sum per minute, so its cost no longer grows with traffic; inbound transfers that do not fit wait in an ordered queue instead of failing; recipients that could never pass funds on are refused on both chains; senders and token ids are compared as bytes; and the guard's ownership moves in two steps. The original proofs of concept no longer reproduce, both contracts are verified source matches, and the live configuration of both chains matches the remediation. Three new issues came from the fixes: the inbound queue has no way out for a transfer that can never be released, governance can still change the bridge's mailbox, which would make past deliveries replayable, and the inbound minimum on aeva-1 must move in step with the guard's; none is exploitable on the live configuration.
Ownership Privileges
The ownership of the bridge has been split between aeva-1 governance, which owns the routes and the bridge mailbox, and a 2-of-3 Safe on Robinhood Chain, which owns both routers and both guards behind its transaction guard. The owners retain full privileges including:
- Governance can create and change routes, raise or remove caps, pause and resume routes and rotate the validator set of the bridge mailbox, in about five minutes.
- Governance can still change the bridge's mailbox through a parameter update, and it can ship a software upgrade that changes any state.
- The Safe can pause the guard, tighten its limits and allowlist at once, and bridge its own tokens like any user.
- After a public 24 hour delay the Safe can replace a router's hook or security module, enrol another remote router, change the guard's validator module, raise limits, transfer ownership or replace its own transaction guard.
- The Safe cannot add a rebalancer or an allowed bridge, set a fee recipient or a fee hook, use the routers' vault functions or renounce ownership: the transaction guard refuses these calls.
- Every loosening by the Safe is scheduled in public at least 24 hours before it can execute, and it executes once.
- Two Safe signers can still change the Safe's owners and threshold and unpause the guard at once; the team accepts this risk while the signers are its own.
- Neither owner can mint AEVA through the bridge: aeva-1 releases native AEVA only from the escrow, and synthetic minting is limited to the bridge's own denominations.
Security Features
The contract implements several positive security features:
- aeva-1 accepts a delivery only from the bridge's mailbox, verified by the validators' 2-of-2 multisig, and refuses a signed mailbox creation.
- Each route keeps a rolling 24 hour cap per direction at a bounded cost, and inbound transfers that do not fit wait in nonce order instead of failing.
- Recipients that could never pass funds on, such as escrows, module accounts and malformed or zero addresses, are refused at the origin before any funds are locked, and again on arrival.
- The guard refuses value, accepts calls only from the mailbox, rolls its daily totals back with any refusal, moves its ownership in two steps and holds no tokens.
Note - This Audit report consists of a security analysis of the Aeva Bridge (the native escrow and synthetic routes on aeva-1, the Hyperlane configuration, AevaBridgeGuard as hook and security module of both Robinhood Chain collateral routers, and AevaSafeGuard as the transaction guard of the Safe that owns them) as released in aevad v1.1.4 and deployed on Robinhood Chain, checked against live state. This analysis did not include economic analysis of the AEVA tokenomics. Moreover, we only audited the bridge for the Aeva team; the staking, rewards and chain-level items are covered by their own reports, Hyperlane core, the stock routers and the off-chain agents were reviewed only in their configuration, and other contracts associated with the project were not audited by our team. We recommend investors do their own research before investing.
Files and details
Findings and Audit result
critical Issues | 1 findings
Resolved
#1 critical Issue
Second-mailbox replay drains the native AEVA escrow because the x/bridge inbound handlers ignore the delivering mailbox
The Hyperlane core module on aeva-1 prevents replay by remembering each pair of delivering mailbox and message id. The x/bridge handler for the native escrow ignores which mailbox delivered a message, and the security module it selects is always the bridge mailbox's own 2-of-2 multisig. Any account can create a further mailbox with any local domain, and the validators' signatures do not bind the destination mailbox. An ordinary account can therefore resubmit an aeva-rh inbound message that was already delivered, together with its original signatures, through a mailbox of its own: the message is treated as new, the signatures still verify, and the escrow pays the recipient again. This can be repeated once per new mailbox, no governance, Safe, validator or relayer key is needed, and both steps pass the ante handler as normal user transactions. The only bound is the inbound cap of 3 000 000 AEVA per rolling 24 hours, which limits the daily rate and not the total. Every past aeva-rh inbound message, about 6.2 million AEVA, is replayable against an escrow of about 894 million AEVA, and the escrow invariant I8n stays satisfied because the balance and the inbound counter move together. The rights handler has the same flaw, with no live route today, and the synthetic route is not affected because the warp handler checks the delivering mailbox.
medium Issues | 3 findings
Resolved
#1 medium Issue
The Safe's control of the routers reaches aeva-1's native escrow and users' approvals, and includes an undocumented rebalance bypass of the guard
Note 2 says the 2-of-3 Safe can replace a router's ISM or hook and that this amounts to control of the routers' collateral. The routers give the same signers more than that. Through addRebalancer, addBridge and rebalance, the Safe can move up to a router's whole balance, LP deposits included, to a contract it chose, without dispatching any message, without the guard being called and without the guard's pause stopping it, and monitoring of the hook and ISM pointers sees nothing. Once a rebalancer is added, that single key can repeat the drain on later inflows without any further Safe signature. A fee recipient set by the Safe can charge each user up to their standing approval on top of the amount, while the guard counts only the payload. Because the router collateral backs the native AEVA released from aeva-1's escrow, the Safe can also bridge in its own 10 000 000 AEVA tokens, receive native AEVA and take the collateral back, repeating at up to 3 000 000 AEVA per rolling day with no limit on the total, while the router balance looks unchanged and the escrow invariant stays green. In one transaction the Safe can take 6 376 702.3 AEVA and 9.082363 USDG from the two routers, and over time it can reach the 893.6 million AEVA escrow until aeva-1 governance pauses the route. None of these functions is configured today. The severity is read in the same way as for the consensus authority override: in both cases the key holders can already reach the same outcome through a documented route, because section 9 note 2 of AUDIT-SCOPE says that setting the ISM is equivalent to control of the collateral and governance can already ship any software upgrade, so the undocumented route widens the documented risk without raising its ceiling, which makes this finding medium because it adds a route that bypasses the guard even while it is paused and can be delegated to a single key, and the override low because it needs a governance vote and is not configured today.
Resolved
#2 medium Issue
Dust transfers make rolling-window pruning exceed the block gas limit and freeze a route direction until governance intervenes
x/bridge stores one window entry per transfer for each route and direction, whatever the amount, and every bridge-out or inbound delivery first prunes every expired entry inside the same transaction, at about 2 096 gas per entry and with no upper bound. Neither chain enforces a minimum amount, and a cap of 0 still records and prunes entries. Once about 47 675 entries expire before the next transfer in one direction, that transfer needs more than the 100 000 000 block gas limit and runs out of gas, its deletions are rolled back, and every later attempt meets the same backlog. No other code prunes the window, changing the route does not reset it and pausing does not clear it, so that direction stays frozen until governance changes the window length. On the outbound side an attacker needs about 128 AEVA in fees and gets the dust back on Robinhood Chain, and the freeze follows about 24 hours later if no other bridge-out happens while the burst expires. On the inbound side about 0.169 ETH of one-wei transfers is enough if the team relayer delivers the burst quickly, and the relayer pays about 400 AEVA of delivery gas for it. No funds are lost, but user transfers in that direction fail with no time limit and the attack can be repeated at the same cost.
Resolved
#3 medium Issue
Robinhood to aeva-1 transfers admitted by the guard's UTC day are held by aeva-1's rolling inbound cap with no refund and no ordering
A transfer from Robinhood Chain locks the tokens in the router at dispatch, and the guard admits it if it fits the guard's per-transfer and per-UTC-day limits. aeva-1 checks its own rolling 24-hour inbound cap only when the message is delivered, and over the cap the delivery fails without recording or refunding anything. Both limits are 3 000 000 AEVA, but the guard's resets at midnight UTC and aeva-1's rolls, so right after midnight the guard can admit a further 3 000 000 while aeva-1's window is still full. Nothing orders the retries, so a later and smaller transfer can take the room first, again and again. Users do not choose the delivery order, the team relayer does, so a user who keeps the window filled can hold another user's transfer only while the relayer delivers newer transfers before it retries the held one, which is what happened live, and as long as that continues the transfer can be held indefinitely at the cost of the user's own tokens. Demand at the cap has the same effect without any attacker. The sender cannot relay the message themselves, because the validators' signatures are stored only on the team's hosts. This is happening on mainnet: message nonce 127, 357 120 AEVA dispatched on 2026-09-30 at 00:18:29 UTC, was overtaken twice when room opened and was still undelivered at aeva-1 height 264 563, 36 hours and 55 minutes after dispatch, and still at height 599 431 on 2026-10-06, about 153 hours after dispatch. Note 4 discloses holds only for the other direction.
low Issues | 6 findings
Resolved
#1 low Issue
A validator's withdraw address can point at the native escrow or the warp account, and on removal its commission is stranded
The native escrow and the warp module account are protected by the x/bridge send restriction but are not on the bank's blocked list, so distribution accepts either of them as a validator's withdraw address. When such a validator is fully unbonded and removed in the staking EndBlocker, distribution's AfterValidatorRemoved hook tries to pay the accumulated commission, the send restriction refuses it, and the SDK only logs the hook error, so the block commits. The hook stops before it moves the outstanding rewards to the community pool and deletes the validator's records. If the operator then creates the validator again, the records are reset and the distribution module holds coins that no record describes, which makes distribution's genesis import panic on an exported state. Only the attacker's own commission is lost and no other account is affected, but an export-based migration would fail until the genesis file is repaired by hand.
Resolved
#2 low Issue
Inbound deliveries can credit the native escrow, the warp account and non-blocked module accounts, and on a future NATIVE_OUT route a delivery to warp would halt the chain
The recipient of an inbound transfer is the 32-byte value the sender passes to transferRemote on Robinhood Chain, and a full 32-byte account such as the native escrow can be named. On aeva-rh the native escrow handler refuses only the escrow itself and the blocked accounts, so the warp, bridge, erc20, evm, feemarket, hyperlane, gov, stakelock and pool accounts are accepted, although the error text says module accounts are refused. On usdg-rh the wrapped warp handler makes no recipient check at all and runs the inner handler with the bridge's context flag, so aeUSD can even be minted to the native escrow. Coins delivered to the escrow, warp, bridge, erc20, evm, feemarket or hyperlane accounts can never leave, and a delivery that aeva-1 does refuse is refused for good after the tokens are already locked in the router. On a NATIVE_OUT route, which does not exist today and cannot exist for aaeva, a delivery to the warp account would lower its recorded collateral without moving any coins, break invariant I8 and halt the chain at the next invariant check, so any user could stop aeva-1 with a dust transfer once such a route is opened.
Resolved
#3 low Issue
aeva-1 accepts a Robinhood recipient with non-zero upper bytes that the routers can never pay, freezing the transfer with no refund
MsgBridgeOut only checks that remote_recipient is 32 bytes of hex. BridgeOut then consumes the outbound window, moves the AEVA into the native escrow or burns the aeUSD, and dispatches a message whose payload recipient is those 32 bytes. On Robinhood Chain both routers are stock HypERC20Collateral from core 12.1.0, whose handler converts the recipient with bytes32ToAddress, and that conversion reverts when the upper 12 bytes are not zero instead of truncating. The guard's verify truncates the same field to its low 20 bytes, accepts the message and states in a comment that the router does the same, the validators' ISM accepts it, and then the router's handle reverts, so the whole process call reverts and the message can never be delivered under any guard configuration. The sender loses the whole transfer: the AEVA stays in the escrow or the burned aeUSD's USDG stays in the router, the outbound window stays used, and there is no refund path. Only the CLI pads 20-byte input, so a pasted 32-byte value, a wallet that builds the field wrongly or any direct API use can trigger it.
Resolved
#4 low Issue
The guard's ownership transfer is single-step, and the role it hands over controls every inbound release
transferOwnership sets the new owner immediately, with no pending owner and no acceptance step. A wrong but valid address signed by the Safe therefore takes the role at once, and in the same transaction the Safe loses pause, setLimits and setValidatorIsm. Whoever controls that address can point setValidatorIsm at any contract that reports module type 5, including one that accepts everything, and raise the limits without a ceiling, after which every message from domain 2383 to either router verifies and collateral can be released. The Safe could then only race to replace the ISM and hook on both routers, which itself needs two of three signatures. The trigger is a mistaken Safe transaction, the live owner is the Safe and there is no pending state today, but the consequence is the full release power that note 2 describes, held by an unintended party.
Resolved
#5 low Issue
A route stored with a mixed-case remote_contract refuses inbound deliveries from its own router
MsgSetRoute accepts a remote_contract in any hex case and SetRoute stores the string exactly as submitted, decoding it only to enrol the warp router. All three inbound handlers, for native escrow, synthetic and rights routes, then compare the message sender rendered as text, which the Hyperlane library always renders in lowercase, with the stored string. A route stored in mixed or upper case therefore refuses every delivery from its own enrolled router as an unknown route, although the warp module's own byte comparison would accept it, while outbound transfers over the same route keep working because that path decodes the stored string. A realistic trigger is a hand-written governance proposal that pastes a router address in its checksummed form, as explorers and the scope document show it. While it lasts, every inbound transfer on the route is refused after the sender's tokens are already locked on Robinhood Chain. It is not permanent: a failed delivery rolls back the replay record, so after governance stores the same contract in lowercase the same messages are delivered and nothing is lost. Tests show the refusal and the recovery on all three route types with the invariants green. It is latent on aeva-1: both live routes are stored in lowercase, at the audit snapshot and at height 600 197, and the team's proposal tooling lowercases router addresses and checks the stored form after each proposal.
Pending
#6 low Issue
Queued inbound transfers that can never be released block their route's queue, and failing ones use up every route's release budget
Since v1.1.4 an inbound transfer that does not fit the window, or that arrives while others wait, is marked delivered and queued, and the EndBlocker releases queued transfers route by route, each from the head of its queue, with one budget of 100 attempts per block shared by all active routes. A queued transfer larger than the route's inbound cap can never fit, so the EndBlocker stops the route at it every block and every later transfer, however small, waits behind it; the same happens when governance lowers the cap below a queued amount. A queued transfer whose release fails for another reason stays at the head and is retried every block, for example on a RIGHT_OUT route whose asset policy refuses the recipient, which is checked only at release; with 100 such entries at the head of a route that comes first in id order, no other route's queue is attempted again. Nothing skips, removes or refunds a queued entry, so only a cap change by governance or a software upgrade frees the route, while the tokens stay locked on Robinhood Chain. Tests on v1.1.4 show a queue frozen for a simulated week behind one transfer above the cap and behind a lowered cap, and a synthetic route's queue never attempted behind 100 failing entries on a native route. It is latent today: the guard's per-transfer limits are far below aeva-1's inbound caps, no cap reduction is planned and no RIGHT_OUT route exists.
informational Issues | 6 findings
Resolved
#1 informational Issue
Inbound routes are resolved by the recipient's internal id only
A Hyperlane recipient is 32 bytes made of a 20-byte specifier, a 4-byte module type and an 8-byte internal id. routeByToken resolves the route from the internal id alone, so a message whose recipient has a different specifier still reaches the same route. Using this would require both validators to sign such a message, and ids cannot collide because the router sequence is global, so there is no impact with honest validators, but the handlers never check the recipient a message names against the route's own token id.
Resolved
#2 informational Issue
The vendored README lists two of the three patch changes
The README of the vendored hyperlane-cosmos describes the store import swap and Router.WrapModule. The patch file also adds the hyperlane/ prefix guard to RemoteReceiveSynthetic, which is the change that stops a remote message from minting aaeva, and its hunk is dated three days after the other two. All three changes are correct. The risk is that a re-vendor which follows the README instead of applying the patch file would silently drop the mint guard.
Resolved
#3 informational Issue
A pause on one side does not stop the other side from taking transfers into a hold, and the documented fast stop leaves aeva-1 bridge-outs open
When only the guard is paused, aeva-1 keeps accepting bridge-outs, and each one escrows AEVA or burns aeUSD, consumes the outbound window for 24 hours and then waits at the guard with no refund. When only the aeva-1 route is paused, Robinhood users keep locking tokens, and after the unpause the backlog meets the rolling inbound window and the excess waits again. The runbook's incident stop is the guard pause plus stopping the relayer, which stops deliveries only because the validators' signatures are kept on the team's hosts. Nothing is lost, but during an incident users on the unpaused side keep moving funds into a hold of unknown length.
Resolved
#4 informational Issue
Router LP deposits are spent on warp releases, and note 11 states the collateral formula backwards
In the stock routers, totalAssets() is the LP side, deposits plus donations minus withdrawals, so bridged collateral is the token balance minus totalAssets() and not totalAssets() less LP deposits as note 11 says. Warp releases are paid from the router's whole token balance without any check against bridged collateral, so once bridged collateral runs out they spend LP deposits and donations while the LP share value stays unchanged and the last LPs cannot withdraw. Both routers hold no LP deposits today, so no LP money is at risk, but anyone following note 11 gets a wrong conservation reading, and a single wei sent straight to a router makes the operators' check report a fault.
Pending
#5 informational Issue
params.mailbox_id can still be changed by governance, and a change makes past deliveries replayable through the new mailbox
Since v1.1.4 MsgUpdateParams refuses changes of ism_id, validators and threshold but still accepts a new mailbox_id. x/core keeps delivered message ids per mailbox, the validators' signatures do not bind the destination mailbox, and the native escrow and rights apps accept a delivery from whichever mailbox params.mailbox_id names, verified by that mailbox's default ISM. A proposal that creates a mailbox with the bridge's multisig as default ISM and points mailbox_id at it, as a mailbox migration naturally would, makes every message ever delivered through the current mailbox deliverable again, and anyone with a delivered message and its public metadata can release the escrow again up to the inbound cap per rolling day. A test on v1.1.4 shows a delivered message paid a second time after such a change, with I8n green. It needs a passed proposal and is within governance's documented trust, but it silently undoes the mailbox binding that closed the replay.
Pending
#6 informational Issue
aeva-1 refuses inbound transfers below min_amount after the guard admitted them unless both minimums are changed in the right order
v1.1.4 applies a route's min_amount to inbound deliveries: a transfer below it is refused at delivery, after its tokens are locked on Robinhood Chain, and that delivery can never succeed. Guard v2 refuses outbound transfers below its own per-router minimum at dispatch, but the two values are set independently, one by an aeva-1 proposal and the other by a Safe transaction. If min_amount is raised on aeva-1 before the guard's minimum, or while smaller transfers are in flight, those transfers stay locked with no refund, the situation the recipient and cap fixes removed elsewhere. Both minimums are 0 today, and the client plans a proposal to set them.