Feb 28, 2026·5 min read·3 visits
The ERC-7984 wrapper fails to validate if the destination confidential token supply acts within cryptographic limits (e.g., euint64). Users wrapping tokens when the supply is near capacity will have their plaintext assets transferred and locked in the contract, but will receive no confidential tokens in return, resulting in a total loss of the deposited funds.
A critical vulnerability in the OpenZeppelin Confidential Contracts library allows for the permanent loss of user funds during token wrapping operations. The issue resides in the `ERC7984ERC20Wrapper` contract, where a discrepancy between the plaintext token supply and the confidential token's cryptographic capacity allows transfers to succeed even when minting the corresponding confidential tokens fails due to overflow.
The vulnerability affects ERC7984ERC20Wrapper.sol within the openzeppelin-confidential-contracts library, specifically versions prior to v0.3.1. This component is designed to bridge standard ERC20 tokens into the ERC-7984 Confidential Fungible Token standard, utilizing Zama's FHEVM (Fully Homomorphic Encryption Virtual Machine) to maintain balance privacy.
The core issue stems from the interaction between standard Ethereum Virtual Machine (EVM) data types and the constrained data types required for Fully Homomorphic Encryption (FHE). While standard ERC20 tokens typically utilize uint256 for balances, confidential tokens often rely on encrypted integers with smaller bit-widths (e.g., euint64) to manage computational overhead.
The wrapper contract acts as a bridge: it accepts a plaintext token transfer and mints an equivalent encrypted amount. However, the system failed to account for edge cases where the plaintext transfer succeeds, but the subsequent minting operation hits the cryptographic upper bound of the confidential token supply. This failure to handle the overflow condition atomically results in state inconsistency.
The root cause is a Missing Upper Bound Check (CWE-190) coupled with Unchecked Return Value (CWE-252) behavior in the wrap function context.
In the FHEVM environment, encrypted integers have strict capacity limits defined by the encryption scheme's parameters. For example, an euint64 type has a maximum value of 2^64 - 1. Standard ERC20 tokens, however, operate on uint256 and may have supplies that far exceed this 64-bit limit.
The vulnerable wrap function executed logically in two steps:
transferFrom on the underlying ERC20 token, moving funds from the user to the wrapper._mint to generate confidential tokens for the user.The flaw logic assumed that if step 1 succeeded, step 2 would also succeed. However, if the addition of the new amount caused the confidential totalSupply to overflow its bit-width capacity, the underlying FHE logic would fail to produce a valid encrypted balance increment. Crucially, this failure did not trigger a transaction revert in the wrapper's scope. Consequently, the EVM committed the plaintext transfer, but the confidential ledger remained unchanged, effectively burning the user's funds into the wrapper contract.
The remediation in Pull Request #268 introduces a preventative check to ensure the wrapping operation remains within safe bounds before any state change occurs.
Vulnerable Logic (Conceptual): In the unpatched version, the contract blindly attempts to convert and mint.
function wrap(uint256 amount) public virtual {
// 1. Transfer plaintext tokens (State change happens here)
IERC20(underlying).safeTransferFrom(msg.sender, address(this), amount);
// 2. Mint confidential tokens
// VULNERABILITY: If this overflows the encrypted type, it may fail silently
// or result in invalid FHE ciphertext without reverting the transaction.
_mint(msg.sender, amount);
}Patched Logic (v0.3.1): The fix enforces a precondition check against the maximum supply of the confidential token type.
function wrap(uint256 amount) public virtual {
// FIX: Check for overflow before transferring funds
// explicit check against the maximum capacity of the confidential storage
uint256 currentSupply = totalSupply();
uint256 newSupply = currentSupply + amount;
// Ensure the new supply fits within the FHE limits (e.g., uint64)
if (newSupply > type(uint64).max) {
revert ERC7984WrapperFull();
}
// Safe to proceed
IERC20(underlying).safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, amount);
}This explicitly prevents the "lock-up" scenario by ensuring the transaction reverts before the user's plaintext tokens are transferred.
An attacker or an unfortunate user can trigger this vulnerability under the following conditions:
ERC7984ERC20Wrapper instance where the underlying confidential token is nearing its maximum capacity (e.g., near 2^64 - 1 for 64-bit FHE implementations).wrap(amount) transaction where current_confidential_supply + amount > max_capacity.transferFrom executes successfully, moving amount of plaintext tokens from the user's wallet to the wrapper contract._mint operation fails to increment the confidential balance due to the overflow constraints of the FHE scheme.The user's plaintext tokens are now owned by the contract, but they possess no confidential tokens to redeem them. Without administrative intervention (which may not exist depending on contract governance), these funds are permanently lost.
Impact: Permanent Loss of Funds The primary impact is the unrecoverable loss of user assets. Unlike a temporary denial of service, this vulnerability results in a state where the asset backing (plaintext tokens) is decoupled from the asset representation (confidential tokens).
Severity Factors:
This vulnerability fundamentally breaks the 1:1 peg invariant required for a functional token wrapper.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
openzeppelin-confidential-contracts OpenZeppelin | < 0.3.1 | 0.3.1 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Integer Overflow / Unchecked Return |
| CWE IDs | CWE-190, CWE-252, CWE-754 |
| Affected Component | ERC7984ERC20Wrapper.sol |
| Attack Vector | Network |
| Impact | Loss of Funds |
| CVSS Severity | High |
The software does not check the return value of a function or method, or fails to handle an exceptional condition (overflow), leading to an inconsistent state.