Zircuit security record

Ethereumzircuit.comX

As of 14 Oct 2026, Zircuit has 4 audit reports by 1 security firm on Trustblock; the latest is by Quantstamp, dated 7 Sep 2026. Those reports list no open critical findings.

Critical findings
No open critical findings
Across 4 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Statuses are the security firms’ own. Trustblock does not review code.

Audits4

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Zircuit Finance - Merkle DistributorSecurity firm: QuantstampDate: Scope: Not recorded. See the reportNo open critical findingsOpen · certificate.quantstamp.com
Zircuit Finance - Circle CCTP AdapterSecurity firm: QuantstampDate: Scope: Not recorded. See the reportNo open critical findingsOpen · certificate.quantstamp.com
Zircuit ZRCSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Zircuit - L2 Upgradeable ContractSecurity firm: QuantstampDate: Scope: Repository at commit e76f03cNo open critical findingsOpen · certificate.quantstamp.com

Findings6

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High000
Medium000
Low033
Low`removePeer` Emits Zeroed Domain Instead of the Actual Removed Values, Breaking Audit Trail ReconstructionZircuit Finance - Circle CCTP Adapter · Quantstamp · 29 Apr 2026Fixed

`CircleCCTPAdapter` maintains a bijection between chain identifiers and Circle CCTP domains through the `chainIdToConfig` and `domainToChainId` mappings, and signals every lifecycle change on a single event, `CCTPPeerSet(uint256 indexed chainId, uint32 indexed domain, address indexed adapter)`. Off-chain indexers, monitoring tooling, and any downstream subgraph rely on this event to mirror peer state. On additions the event carries the real domain and adapter values; on removals the current implementation emits `CCTPPeerSet(chainId, 0, address(0))` to encode "cleared". However, `0` is the canonical Circle CCTP v2 domain identifier for Ethereum mainnet — a legitimate value that may be registered as a peer at any time. Emitting `0` in the `indexed domain` topic as a removal sentinel is indistinguishable on-chain from an event describing a peer whose domain is Ethereum. Indexers that filter on `domain = 0` to track Ethereum-related peer changes will falsely match every `removePeer` emission, and indexers that reconstruct history by pairing set with remove will lose the original domain of the peer being removed because the topic overwrites it with a value that looks like an Ethereum registration. This could cause off-chain systems to misclassify peer removals as Ethereum peer registrations, corrupt historical peer state reconstructions, and complicate observability once Ethereum is legitimately registered. There is no on-chain fund impact, but the ambiguity is avoidable and undermines the otherwise clean event-based audit trail the contract provides.

Open the report
LowNo ERC-20 Token Recovery FunctionZircuit Finance - Circle CCTP Adapter · Quantstamp · 29 Apr 2026Fixed

`CircleCCTPAdapter` has no function to recover ERC20 tokens that land in the contract outside of the normal `receiveFunds` flow. In practice, USDC cannot get stuck via the protocol path — `messageTransmitter.receiveMessage()` and the subsequent transfer to the router are atomic, so any failure rolls back the mint entirely. However, if USDC or any other ERC20 is sent directly to this contract address by mistake (e.g. a user error, a failed airdrop, or dust from an unrelated interaction), it is permanently unrecoverable. Every other adapter in this package ( `OFTBridgeAdapter`, `ProtoCCTPGatewayAdapter`, `ArbitrumAdapterL1`, and `ArbitrumAdapterL2`) has a `RESCUE_ROLE`-gated recovery mechanism.

Open the report
LowReceive-Side Validation Skips Circle CCTP Message HeaderZircuit Finance - Circle CCTP Adapter · Quantstamp · 29 Apr 2026Fixed

`CircleCCTPAdapter.receiveFunds()` authenticates an inbound CCTP v2 message by forwarding it to `messageTransmitter.receiveMessage()` and then hands it to `_parseReceivedMessage()`. The parser reads fields from the 228-byte `BurnMessageV2` body, `mintRecipient`, `amount`, `feeExecuted`, `messageSender`, and the trailing `hookData`, and compares each against state maintained by the adapter (the `domainToChainId` mapping, the stored peer adapter for the resolved source chain, and `address(this)`). These three body-level comparisons are the adapter's entire authorization model for inbound messages. The parsed `destAddress` and `extraData` are then passed to `router.handleReceivedFunds`, which gates the final destination through `Factory.isAuthorizedBridgeAddress()`. However, Circle's `MessageTransmitterV2.sendMessage()` is a permissionless entry point that produces valid, attestable messages whose body is entirely attacker-controlled bytes. The adapter never inspects the 148-byte message header, in particular the `sender` field (which for a genuine burn message equals the source-chain `TokenMessengerV2`) and the `recipient` field (which equals the destination-chain `TokenMessengerV2`). An attacker on a registered peer chain can therefore craft a message whose body is byte-compatible with `_parseReceivedMessage()` (correct `mintRecipient`, `messageSender` equal to the registered peer adapter, any chosen `amount`, any `feeExecuted`, any `destAddress` encoded in the hook data) have Circle attest it, and submit it via `receiveFunds` on the adapter. Circle dispatches the hook payload to an attacker-chosen no-op handler, so no USDC is minted to the adapter, yet the body-level checks all pass because the attacker wrote the bytes the parser expects. This could allow any USDC residing in the adapter — operational dust, accidental transfers, or balances introduced by a future refactor — to be routed to a vault of the attacker's choosing through `router.handleReceivedFunds()`. In the current integration, the destination is constrained to addresses that `Factory.isAuthorizedBridgeAddress()` has whitelisted, so the funds end up in a Zircuit-authorized vault rather than an attacker-controlled wallet; the attacker gains nothing and the worst case is a bounded shift of residual balance between authorized cluster vaults. The residual business impact is therefore informational, but the adapter has no defense-in-depth for future integrations that may permit non-cluster destinations or for scenarios in which the adapter accrues a non-trivial balance.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="zircuit"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us