Polygon zkEVM Security Review: Four Critical Findings Fixed

Polygon zkEVM Security Review: Four Critical Findings Fixed
Share

Before Polygon zkEVM went live, the team put its full technical stack up for review, including smart contracts, a zero-knowledge prover (software that generates cryptographic proofs of computation), and the low-level assembly code that reimplements the Ethereum Virtual Machine. The Hexens security review published in February 2023 turned up 16 findings across that stack, four of them critical. Every one was fixed.

Key Takeaways

  • The review covered four repositories: zkevm-contracts, zkevm-proverjs, zkevm-rom, and zkevm-storage-rom.
  • Hexens identified 16 findings in total: 4 critical, 1 high, 1 medium, 3 low, and 7 informational.
  • All 16 issues were confirmed fixed by the Polygon team and validated by Hexens.
  • Two of the four critical findings were missing constraints in PIL (Polynomial Identity Language, the circuit description language used to define the prover's rules), meaning an attacker could have constructed false proofs.
  • Hexens built a static analysis tool for the PIL language during the course of the audit, an artifact that did not exist before this engagement.

What Polygon zkEVM Is Trying to Do

A zkEVM (zero-knowledge Ethereum Virtual Machine) is a layer-2 scaling network that processes transactions off the main Ethereum chain and then posts a compact cryptographic proof to Ethereum to certify that those transactions were valid. The promise is high throughput at lower cost, with Ethereum-level security guarantees backed by the proof.

The technical challenge is that implementing every Ethereum opcode (instruction) inside a zero-knowledge proof system requires rewriting the entire EVM from scratch in a circuit-friendly language. Polygon's approach uses PIL to describe arithmetic constraints, zkASM (zero-knowledge assembly) to implement opcode logic, and a Solidity bridge contract to anchor the system on Ethereum. Any bug in any of those three layers can break the security model of the entire chain.

Why This Surface Is Unusually Hard to Get Right

A conventional smart contract audit checks Solidity or Vyper source for logic errors, access control gaps, and known vulnerability patterns. Auditing a zkEVM means doing all of that, and then checking whether the mathematical constraints encoded in the circuit actually match what the assembly code does, and whether the assembly code actually matches what the Ethereum Yellow Paper specifies.

The gaps between those three layers, specification, circuit, and implementation, are exactly where the most dangerous bugs hide. A constraint that is missing or slightly wrong does not crash the system visibly. It silently widens the set of proofs the verifier will accept, which means an attacker could potentially prove things that never happened.

That problem showed up twice in this review, both times at critical severity.

What the Review Found

Two Circuits That Accepted False Proofs

The first missing-constraint finding lived in storage.pil. The PIL circuit governing SMT (Sparse Merkle Tree) inclusion checks lacked a constraint that should have enforced a specific relationship between values. Without it, a malicious prover could have constructed a proof of inclusion for a leaf that does not actually exist in the tree, a direct attack on the integrity of state proofs.

The second missing-constraint finding was in utils.zkasm and main.pil. This one was more alarming in scope: the gap allowed an attacker to redirect execution flow inside the prover, meaning arbitrary computation could have been substituted for the intended program. Both issues were fixed.

A Balance That Could Be Inflated from Thin Air

A third critical finding sat in process-tx.zkasm and precompiled/identity.zkasm. An incorrect context (CTX) assignment during transaction processing could cause a random amount of Ether to be added to the sequencer's (the node that orders and submits transaction batches) balance. The value was not stolen from any user account; it was effectively fabricated, which breaks the accounting invariants the bridge contract depends on. Fixed.

An ERC-777 Re-Entrancy in the Bridge Contract

The fourth critical finding was in PolygonZkEvmBridge.sol and is the most recognizable class of vulnerability to anyone who follows DeFi exploits. ERC-777 is a token standard that allows token transfers to trigger a callback in the recipient contract. If that recipient is malicious and the bridge does not update its state before making the external call, the recipient can re-enter the bridge and drain funds before the original transaction completes. The fix involved updating the state before any external interaction.

A Bug That Could Freeze Batch Verification

The single high-severity finding was in main.zkasm and create-terminate-context.zkasm. A bug in how the prover handled MAX_MEM_EXPANSION_BYTES (set to 2^22 minus 32, the ceiling on memory that can expand within a batch) could cause batch verification to halt entirely. A halted verifier means no proofs get accepted on-chain, which is effectively a denial-of-service against the entire layer-2. Fixed.

Circuit and EVM Spec Divergences

Several lower-severity findings documented places where the zkEVM implementation diverged from the standard Ethereum specification. The ecrecover precompile (a function used to recover a signer's address from a cryptographic signature) used an off-by-one value for FNEC_DIV_TWO: the implementation used 57896044618658097711785492504343953926418782139537452191302581570759080747169 where the correct value is ...747168. Transaction RLP (Recursive Length Prefix, Ethereum's binary encoding format for transactions) decoding also differed from the mainnet EVM in edge cases, and GASLIMIT and CHAINID accepted sizes beyond what mainnet allows. Each of these was fixed.

A Tool Built During the Audit

One detail worth noting: the PIL language had no static analysis tooling when the engagement began. Hexens built one during the audit. That tooling surfaced the permutation constraint discrepancies documented among the informational findings, gaps between what the verifyPil tooling expected and what the STARK (Scalable Transparent Argument of Knowledge) generator actually enforced. The tool itself is a durable output of the review, not just the findings list.

Frequently Asked Questions

What repositories were included in the Polygon zkEVM security review? The scope covered four GitHub repositories maintained by 0xPolygonHermez: zkevm-contracts (Solidity bridge and rollup contracts), zkevm-proverjs (the JavaScript-based zero-knowledge prover), zkevm-rom (the zkASM opcode implementations), and zkevm-storage-rom (storage-related assembly).

What does a missing PIL constraint actually mean for security? PIL constraints are the mathematical rules that define what a valid proof looks like. If a constraint is missing, the verifier's acceptance set is too wide: it will accept proofs that prove things the real system would never produce. In the worst case that means proving false state transitions, such as an inclusion in a Merkle tree that does not exist.

Were any of the 16 findings left unresolved? No. All 16 findings, across all severity levels, were fixed by the Polygon development team and the fixes were validated by Hexens. The one nuanced case is the call depth check finding, where the report notes there was no visible security impact at the time of writing because EIP rules limit forwarded gas to 63/64ths of remaining gas, making the 1024-call-depth limit practically unreachable. The issue was nonetheless treated as fixed.

Why did the review cover assembly code and not just Solidity contracts? Polygon zkEVM reimplements the entire EVM in zkASM to make transaction execution provable inside a zero-knowledge circuit. That assembly layer is as much a part of the security boundary as the Solidity contracts are. A bug in the assembly, like the context-assignment error that could inflate the sequencer balance, can undermine guarantees that the contract layer assumes to be true.

What is the ERC-777 re-entrancy risk, and is it specific to zkEVM? Re-entrancy via ERC-777 token callbacks is a known Solidity vulnerability pattern that can appear in any contract that handles token transfers without following the checks-effects-interactions pattern (update state before making external calls). It is not unique to zkEVM; it is a risk in any bridge or vault contract that interacts with ERC-777 tokens. The Polygon team fixed it in PolygonZkEvmBridge.sol.

Reviewing a zkEVM is a different discipline from reviewing a conventional DeFi protocol. It requires reading circuit constraint files, assembly ROM, and Solidity simultaneously, and checking that all three layers agree with each other and with the Ethereum specification. The full Hexens report on Polygon zkEVM documents every finding, path, and fix commit, and is worth reading for anyone building on or auditing similar ZK rollup stacks.

Community members

[ Our community ]

[ Community hires ]