zkSync — disclosed vulnerability reports and payouts
Every publicly disclosed and closed bug bounty report we hold for zkSync, with our own summary of each finding and a link to the original disclosure.
- Reports indexed
- 29
- Total paid
- $0
- Critical
- 0
- Largest payout
- $0
This page collects the 29 closed, publicly disclosed zkSync reports indexed on CoinBuggie. Nothing here is active or unpatched — every entry was published by the programme or the researcher after remediation.
The findings concentrate in Bridge exploit, Logic error, Integer overflow / underflow, Reentrancy, Access control, across EVM-Solidity. Reading a single protocol end to end is the fastest way to see which assumptions its codebase repeatedly gets wrong, which is usually a better predictor of where the next finding lives than the category alone.
Use the vulnerability class links below to compare these findings against the same bug class in other protocols.
What reviewers look for
- Bridge exploit findings disclosed against zkSync
- Logic error findings disclosed against zkSync
- Integer overflow / underflow findings disclosed against zkSync
- Reentrancy findings disclosed against zkSync
- Access control findings disclosed against zkSync
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
zkSync: User might be able to double withdraw during migration
During zkSync Era's three-step L1 bridge migration, a user could withdraw the same ERC20 funds twice. Because L1ERC20Bridge.sol is upgraded and its funds migrated to L1SharedBridge only at the final step, a withdrawal whose L2 batch number equals or exceeds the pre-defined eraFirstPostUpgradeBatch bypasses the _isEraLegacyWithdrawal() legacy-status check, letting the user finalize first on the old bridge and again on the shared bridge. The judge upheld a medium severity over the sponsor's Low dissent, ruling that the flaw is real under contract-permitted operations even if the operator could avoid finalizing the upgrade batch.
zkSync: L2SharedBridge l1LegacyBridge is not set
zkSync's L2SharedBridge initialize() function validates the legacy L1 bridge address parameter but never stores it in the l1LegacyBridge storage slot, leaving it permanently address(0). Because finalizeDeposit() authorizes legacy-bridge-sourced messages against that never-set field, any deposit initiated through the old L1ERC20Bridge during the migration window — after the L2 bridge is upgraded but before the L1 bridge is upgraded — fails validation and cannot be finalized. This creates an availability gap where bridged ERC20 deposits are blocked during the intended migration sequence. The fix is a single assignment of the legacy bridge address in the Era-chain initialization branch.
zkSync: Freezed Chain will never be unfreeze since `StateTransitionManager::unfreezeChain` is calling `freezeDiamond` instead of `unfreezeDiamond`
In zkSync's StateTransitionManager, the `unfreezeChain` function mistakenly calls `freezeDiamond()` on the target chain's state-transition diamond instead of `unfreezeDiamond()`, so the dedicated unfreeze entrypoint re-freezes rather than releases a chain. No other function in StateTransitionManager.sol invokes `unfreezeDiamond`, leaving the manager-level recovery path permanently broken, though the diamond's own admin retains a separate unfreeze route. The judge confirmed the copy-paste error as medium severity because the alternative admin path prevents a true permanent lockout. The official fix is a one-line change plus a corrected NatSpec comment.
zkSync: State transition manager is unable to force upgrade a deployed ST, which invalidates the designed safeguard for 'urgent high risk situation'
zkSync's protocol documentation promises that the StateTransitionManager (STM) can force-upgrade a deployed state transition (ST) contract in an urgent high-risk situation, but the implementation contains no reachable code path for that safeguard. The two upgrade entry points on the Admin facet are both inaccessible to the STM after a chain's genesis: upgradeChainFromVersion allows the chain admin or STM but nothing on StateTransitionManager calls it, while executeUpgrade is STM-only yet is only invoked during _setChainIdUpgrade, which runs solely inside createNewChain. A deployed ST can therefore perform or postpone upgrades at its own convenience, leaving the documented emergency force-upgrade mechanism as dead code. The sponsor confirmed the finding and the judge upheld a medium severity assessment on a low-likelihood scenario.
zkSync: `paymaster` will refund `spentOnPubdata` to user
In zkSync's bootloader refund routine, the gas spent on pubdata is only deducted at the very end of the transaction. When a paymaster is present, refundCurrentL2Transaction tells the paymaster's postTransaction hook its maximum refundable gas is gasLeft + reservedGas, without subtracting spentOnPubdata. Because the paymaster trusts this inflated cap and refunds the user accordingly, the user receives ETH for gas that the bootloader separately earmarks for pubdata costs, producing an economic over-compensation on any paymaster-sponsored transaction. The zkSync team and the Code4rena judge both confirmed the flaw, though the final severity was set to medium given the rarely-used paymaster path.
zkSync: `Mailbox.requestL2Transaction()` checks the deposit limit of `msg.sender` (`L1WethBridge`) instead of the real depositor of weth from L1, as a result, after certain time, nobody will be able to deposit weth anymore from L1
zkSync's L1 WETH deposit flow routes through L1WethBridge and Mailbox.requestL2Transaction, which enforces a per-depositor deposit cap against msg.sender. Because msg.sender at that point is the L1WethBridge contract rather than the actual depositor, the cap is consumed by the bridge address shared by all users, not per-user. Once cumulative deposits reach the configured limit, every subsequent WETH deposit reverts even though individual users remain well under their own limits. This creates a self-inflicted denial-of-service that eventually locks all WETH bridging to L2, with the PoC demonstrating the failure once total deposits cross the cap.
All reports in this group
- zkSync: Reduction gate in binop operation is unsafeInteger overflow/underflow$0
- zkSync: Attacker can manipulate the sorted queue in log sorter to emit reverted logs and eventsLogic error$0
- zkSync: Version hash is not correctly enforced in code unpackerLogic error$0
- zkSync: Nonce ordering of EOA can be updated to "arbitrary" through an L1 txLogic error$0
- zkSync: Synchronization Issue Between L1 and L2 UpgradesReentrancy$0
- zkSync: EIP-155 is not enforced, allowing attackers/malicious operators to profit from replaying transactionsLogic error$0
- zkSync: Loss of funds for the sender when ``L1->L2`` TX fails in the bootloader on L2Reentrancy$0
- zkSync: TransactionValidator checks intrinsic costs against wrong valueLogic error$0
- zkSync: Operator can steal all gas provided by ANY user for `L1→L2` transactionsInteger overflow/underflow$0
- zkSync: Nonce Behavior Discrepancy Between zkSync Era and EIP-161Logic error$0
- zkSync: Attacker can forge arbitrary read value from memory in case `skip_if_legitimate_fat_ptr`Logic error$0
- zkSync: Deployment Nonce Does not Increment For a Reverted Child ContractLogic error$0
- zkSync: Missing range constraint on remainder check in `div` opcode implementationInteger overflow/underflow$0
- zkSync: Lack of access to ETH on L2 through ``L1->L2`` transactionsLogic error$0
- zkSync: Incorrect max precompile addressLogic error$0
- zkSync: Potential Gas Manipulation via Bytecode CompressionLogic error$0
- zkSync: Missing constraint on remainder in `shr` opcode implementationLogic error$0
- zkSync: `Mul/div` relation should not be enforced when divisor is zeroLogic error$0
- zkSync: Governance logic may enter a deadlockAccess control$0
- zkSync: Wrong encoding of the data in the `sendCompressedBytecode` functionAccess control$0
- zkSync: Discrepancy in Default Account BehaviorLogic error$0
- zkSync: Unit difference between transaction encoding and bootloader memory constantLogic error$0
- zkSync: Discrepancy in ECRECOVER Precompile when Using `Delegatecall`Signature replay$0