fix: Security Audit — CallbackValidation.sol#40
Open
rroland10 wants to merge 1 commit intoEthereumCommonwealth:mainfrom
Open
fix: Security Audit — CallbackValidation.sol#40rroland10 wants to merge 1 commit intoEthereumCommonwealth:mainfrom
rroland10 wants to merge 1 commit intoEthereumCommonwealth:mainfrom
Conversation
- Add descriptive revert reason string 'CVF' to require statement in verifyCallback to improve debuggability and prevent silent failures - Update NatSpec documentation to accurately reference Dex223 instead of Uniswap V3, and clarify that token parameters must be ERC-20 addresses - Add @dev documentation explaining the CREATE2-based validation mechanism Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security Audit Report:
CallbackValidation.solFile:
contracts/dex-periphery/base/CallbackValidation.solAuditor: AI-assisted security review
Severity Scale: Critical / High / Medium / Low / Informational
Executive Summary
A thorough security audit was performed on
CallbackValidation.sol, a library used by the Dex223 periphery contracts (SwapRouter,LiquidityManagement,Quoter223) to validate that swap/mint callbacks originate from legitimate pool contracts. The library uses CREATE2-based address derivation to verify callers.The audit identified 1 Medium and 2 Informational findings. All have been fixed in this PR.
Vulnerability 1 — Silent
requireFailure (Missing Revert Reason)CallbackValidation.sol:35Description
The core
requirestatement inverifyCallbackhad no revert reason string:When a callback validation fails (i.e., a malicious or misconfigured contract calls a periphery callback), the transaction reverts with an empty error. This has several negative consequences:
Debugging difficulty: Developers and users cannot distinguish this revert from other empty reverts in the call stack (e.g., out-of-gas, failed low-level calls, assert failures). In a complex multi-hop swap through
SwapRouter.exactInput(), an empty revert is nearly impossible to diagnose.Off-chain tooling breakage: Monitoring systems, block explorers, and transaction simulation tools (Tenderly, Etherscan, etc.) cannot categorize or alert on this specific failure mode. This makes it harder to detect active exploitation attempts where an attacker tries to invoke callbacks from a non-pool address.
Increased attack surface for phishing: When users see a generic "Transaction reverted" error, they may retry with different parameters or increased gas, potentially falling victim to social engineering attacks that exploit the confusion.
Gas cost is negligible: Adding a short reason string (
'CVF'= 3 bytes) costs only ~200 extra gas on the revert path, and zero gas on the success path. This is insignificant compared to the swap operation (~150k+ gas).Fix Applied
The
'CVF'(Callback Validation Failed) error code follows the project's existing convention of short uppercase error codes (e.g.,'LOK','AI','TLU','TLM','TUM'used elsewhere in the codebase).Vulnerability 2 — Incorrect NatSpec Documentation (Token Standard Ambiguity)
CallbackValidation.sol:10-14Description
The NatSpec documentation referenced "Uniswap V3" instead of "Dex223" and did not clarify that the
tokenA/tokenBparameters must be ERC-20 addresses (not ERC-223 addresses).This is critical context in the Dex223 dual-standard architecture because:
Dex223Factory.createPool()function populates thegetPoolmapping for all 8 combinations of ERC-20/ERC-223 token pairs (lines 104-112 ofDex223Factory.sol).PoolAddress.computeAddress()derives the pool address using only the ERC-20 token addresses (since pools are deployed via CREATE2 withkeccak256(abi.encode(token0_erc20, token1_erc20, fee))as the salt).verifyCallback, the computed address would be wrong, causing therequireto always fail — effectively breaking swaps and mints for that path.The existing callers (
SwapRouter.uniswapV3SwapCallbackat line 165,Quoter223.uniswapV3SwapCallbackat line 100,LiquidityManagement.uniswapV3MintCallbackat line 42) all correctly pass ERC-20 addresses because thePathlibrary encodes ERC-20 addresses. But future integrators who write custom periphery contracts could easily make this mistake without proper documentation.Fix Applied
Updated NatSpec to:
tokenA/tokenBmust be ERC-20 addresses@devtag explaining the CREATE2 validation mechanismVulnerability 3 — Missing Library-Level Documentation
CallbackValidation.sol:8Description
The library had only a single-line
@noticewith no@devdocumentation explaining how the validation works. For a security-critical library that is the sole defense against callback spoofing attacks, this is insufficient.Without clear documentation of the CREATE2-based verification mechanism, auditors and developers may not fully understand the security assumptions:
POOL_INIT_CODE_HASHinPoolAddress.solis correct and matches the actual deployed pool bytecode.factoryaddress passed to the function is the canonical Dex223 factory.Fix Applied
Added comprehensive
@devdocumentation explaining the validation mechanism and its security properties.Additional Security Observations (No Code Changes Required)
Observation A — POOL_INIT_CODE_HASH Dependency
The security of
CallbackValidationdepends entirely onPoolAddress.POOL_INIT_CODE_HASH(currently0x2ed8d490...). If this hash becomes stale (e.g., after a pool contract upgrade that changes bytecode), all callback validations would fail, breaking the entire periphery. This is a known operational risk, not a code vulnerability — but the hash should be verified against the actualDex223Poolcreation code after any compiler or contract changes.Observation B — ERC-223 Token Address in Path Encoding
The
SwapRouterandQuoter223usePath.decodeFirstPool()to extract token addresses from the encoded path. The path encoding uses ERC-20 addresses by convention. If a user constructs a path with ERC-223 addresses instead, theverifyCallbackwould compute a wrong pool address and revert. With the new'CVF'error code, this failure mode is now diagnosable.Observation C — No
extcodesizeCheck on Computed Pool AddressThe
verifyCallbackfunction does not check whether the computed pool address has deployed code. Ifmsg.senderhappens to equal a CREATE2-derived address for a pool that hasn't been deployed yet, the validation would pass. However, this is not exploitable because:msg.sendermust have code to call a function).Summary of Changes
contracts/dex-periphery/base/CallbackValidation.sol'CVF'torequirestatement; updated NatSpec documentation to reference Dex223 and clarify ERC-20 token address requirement; added@devdocumentationTest Plan
CallbackValidation.solcompiles without errors under Solidity 0.7.6SwapRouter.solcompiles without errors (usesCallbackValidation.verifyCallback)LiquidityManagement.solcompiles without errors (usesCallbackValidation.verifyCallback)Quoter223.solcompiles without errors (usesCallbackValidation.verifyCallback)'CVF'error codePOOL_INIT_CODE_HASHinPoolAddress.solmatches the keccak256 ofDex223Poolcreation codeMade with Cursor