Post-mortem: Securing Farfadet - the 6.4 to 6.6 disclosures

This is a joint post from Nomadic Labs, TriliTech & Functori.

This post publicly discloses the vulnerabilities that prompted the last three Etherlink Farfadet kernel upgrades: 6.4, 6.5, and 6.6, along with a technical description of each issue and how it was addressed.

None of the vulnerabilities discussed below were exploited.

Most of the vulnerabilities patched by Etherlink 6.4, 6.5 and 6.6 were uncovered through internal audits that systematically use agentic AI to help validate security properties. We’re continuing this effort to improve Etherlink’s security and robustness, and to surface any remaining vulnerabilities.

We’d like to thank the external security researchers who have responsibly disclosed findings through the Tezos Foundation bug bounty program, as well as the bakers who voted swiftly on each governance proposal and helped keep Etherlink secure.

Etherlink 6.4

The Etherlink 6.4 kernel went live June 11th 2026 on block #45,018,602.

This upgrade addressed issues that surfaced after the activation of Etherlink 6.3, uncovered through internal stress-testing and audit campaigns.

Delayed-inbox hardening. Forced-inclusion (delayed inbox) transactions cannot be dropped by the sequencer. If one of them triggered an execution error, that error bubbled up and aborted the whole block, meaning a single delayed transaction could halt block production.

To address this issue, errors from applying delayed transactions are now downgraded to invalid transactions instead of aborting the blueprint. The transaction is skipped and removed from the delayed inbox on promotion, while normal non-delayed transactions still fail as before. See commit 81ede4370f1b195b390e17e72635533c71c13449 for further details.

Reject oversized withdrawal messages. A withdrawal with an attacker-controlled large payload data could produce an outbox message larger than the SDK serialization limit. The EVM transaction itself succeeded, but serialization would fail later when queueing the outbox message.

To mitigate, withdrawal messages are now size-checked before being accepted. The kernel serializes the message upfront using the same logic as queueing, and if it exceeds the outbox size limit the precompile reverts immediately, so no oversized/unserializable message is ever produced. See commit 6d72b83ff24316e4b329ed1078739b60ee6593f1 for details.

Correct sequencer governance contract. After 6.3 shipped, it was discovered that the intended sequencer governance contract had been incorrectly deployed. This upgrade updates the kernel to point to the correct governance contract on Tezos L1. See commit 86a95a45de14577ed47cc2117b0bed12f40a6daf.

Etherlink 6.5

The Etherlink 6.5 kernel was activated June 27th 2026 at block #46,606,524.

This upgrade was prompted by a report received through the Tezos Foundation bug bounty program. The exploit was revealed to be a vulnerability related to the FA bridge, where an attacker could potentially claim a deposit multiple times.

The underlying issue was that the ordinary checkpoint, checkpoint_commit, and checkpoint_revert functions mirror state across both the inner REVM journal and the LayeredState, but create_account_checkpoint only delegates to the inner journal. REVM calls this function when opening CREATE frames, and later closes them via checkpoint_commit/checkpoint_revert.

Because Etherlink 6.4 never opened the matching LayeredState checkpoint for a CREATE frame, a failed CREATE caught after a successful FA bridge claim reverts the previous LayeredState depth - undoing the deposit-removal and ticket-balance bookkeeping, while leaving the EVM proxy mint committed. The result is that the same deposit ID remains claimable again.

Immediate mitigation. To stop the exploit path while a proper kernel fix was prepared, we worked with the sequencer operator, Optimistic Labs, to deploy a sequencer-side patch that pairs every deposit operation with its corresponding claim atomically, effectively preventing the attack.

Enforce kernel state consistency. To fully address the root cause, we applied a patch to the kernel and proposed the Etherlink 6.5 upgrade. See commit bdf658c2e9fb327849a7a22c2f61986c951912c0 for the fix.

Etherlink 6.6

The 6.6 kernel was activated in block #48,571,992 on July 18th 2026.

This was a hardening upgrade addressing a small backlog of accumulated issues. In each case we already had monitoring and mitigations in place, and had seen no evidence of attempted exploitation, but we wanted to close the underlying risk properly in the kernel itself, rather than continue relying on external mitigations. All of these issues were uncovered through internal auditing and testing.

Reject invalid signatures for sequencer key changes. The sequencer-key-change precompile treated Ok(false) from signature verification as success, and only rejected actual verification errors. That meant a well-formed but invalid secp256k1/P256

signature could authorize a sequencer key rotation. While this was exploitable in the kernel, we had deployed a mitigation that would prompt the sequencer to override any attempt of key rotation by posting an additional operation that would effectively revert it. That is valid as the activation of key rotations is delayed.

To address properly, the check has been tightened to reject anything except a successful true verification result, so both invalid signatures and verification failures are now rejected. See commit 25d1dd4f87728698d751fb4da21f2d4b91d5ab39 for the code changes.

Prevent sequencer key storage corruption for overrides with shorter keys. The issue was uncovered through testing key rotation on Etherlink Shadownet which itself triggered an incident where Etherlink Shadownet was not operational for an extended period of time. The culprit is that the kernel overwrote the stored sequencer key in place without truncating the old value. If a new key encoding was shorter than the previous one, stale trailing bytes remained, corrupting the stored key and potentially breaking signature validation / sequencer rotation.

To address, the write path was changed to use a full overwrite (store_write_all) so the stored value is replaced and truncated to the exact new length. See commit 6bf7fe1db60d94a75592562d927ededc993ac208 for details.

Prevent replayable sequencer key change requests. A captured valid public key signature key-change request could be resubmitted indefinitely. An attacker could use this to keep replaying a pending change and reset its activation, and potentially reuse signatures across contexts. In practice on Etherlink we’ve had no key-rotation requests on mainnet, which is why this could not have been exploited up until this point.

To prevent any future exploits, the signed payload has been bound to a domain-separation tag, the chain ID, and a monotonic sequencer-change counter. The counter is bumped when a precompile-based change is stored, making that signed request single-use, and the counter handling was made atomic with layered-state/journal logic so reverts roll it back correctly. See commit 0e0346d044402fa3141bbb6f8c1d87cc769514d0.

Prevent oversized RLP U256 fields to trigger panics. RLP decoding passed arbitrarily long byte strings into U256::from_little_endian, which asserts on inputs longer than 32 bytes. A malicious oversized field in a blueprint chunk could therefore panic the kernel before signature checks, letting any L1 account cause a rollup-node wedge/DoS.

This happens in the decode step, which sits above both the sender/envelope handling and verify_signature. That makes it reachable by any L1 account – no sequencer key or valid signature required.

A WASM trap is a recoverable PVM outcome and not a fault of the rollup: it simply means the kernel fails to produce that particular block. The PVM’s specified behavior is to set the stuck flag and carry on, so evaluation continues to the next level on both the slow PVM and fast execution. The rollup keeps progressing either way.

The risk, however, is that because triggering a trap is cheap, an attacker could flood the inbox with faulty blueprints, and doing so at a scale that risks slowing Etherlink down significantly thus posing a liveness attack.

To address, the decoder now explicitly rejects U256 fields longer than 32 bytes with a normal decode error instead of panicking. See commit 0e0346d044402fa3141bbb6f8c1d87cc769514d0 for the changes.

Keeping Etherlink Mainnet secure

We’re grateful to the researchers who have contributed through the Tezos Foundation bug bounty program. These reports matter especially now, as we approach the crucial moment that would make Tezos X a reality. We are actively working on the next upgrade of Etherlink, which will be a major stepping stone toward full-fledged Michelson and EVM interoperability for Tezos X.

If you are a security researcher, we strongly encourage you to look into Etherlink and other Tezos ecosystem projects. The bug bounty program is the right channel, and your scrutiny will be fundamental to allowing Etherlink and Tezos X to keep evolving safely.

1 Like