Full Report
The Horton Principle is a principle that should always be followed in cryptography: "mean what you sign and sign what you mean". Any time this can be violated, there is a major security problem. The Wyvern protocol is a decentralized digital asset exchange running on Ethereum. This is the standard listings and offers style of market, such as trading NFTs. Wyvern listings contain different parameters used to indicate listing or offer information and authenticate other involved smart contract calls. This is aggregated into a single commitment that the user signs and the contract checks. This is done in order to save funds, since it is signed off chain, and can be signed with expiration times as well. Pretty neat functionality! Aggregating data is sketchy business if you come from the world of website hacking. The bytes being concatenated had no delimiter. Why is this bad? Consider A as 0x01 and B being 0x0101. If we concatenate A + B together, we end up with 0x010101. However, the signed data would be the same if A was 0x0101 and B was 0x01! This violates Horton's Principle mentioned above. In the context of the smart contract, this means we can change the parameter that the bytes were signed for! Practically, this can be exploited in a very bad way. In the Wyvern system, NFTs are swapped for other digital items. To allow this, the Wyvern listings have a calldata field to allow a callback with specific parameters. In some cases, the calldata must be mutated at the time of fulfillment. This can be done by a replacementPattern - a bitmask to alter the calldata. This is necessary for OpenSea, the address of the offer taker must be added to the calldata. In calldata, the first 4 bytes are the function selector. In the context of OpenSea, we need to call transferFrom(address,address,uint256). Using the modification primitive from above, an attacker could shift bits between the callData and replacementPattern to modify the function selector! The closest selector is getApproved(uint) at only 10 bits of difference. There is a 1 in 1024 chance that a random 4 byte bitmask (with the shift) has the correct bitmask to change the selector to the proper location. Additionally, the address could be started at any point in the pattern. Hence, this reduced the exploit down to 1 out of 64 offers being exploitable. Using the getApproved(0) primitive, an attacker could have taken WETH from these users, despite them never approving or still owning the NFT. Overall, a super interesting bug that was never exploited. Handling signing and data parsing is not nearly as simple as one would think.
Analysis Summary
# Vulnerability: Wyvern Protocol Concatenation Ambiguity Leading to Arbitrary Function Selector Manipulation
## CVE Details
- CVE ID: Not explicitly assigned in the text (Assumed post-hoc assignment possible, but not provided)
- CVSS Score: Not explicitly provided (Described as "critical")
- CWE: CWE-133 (Improperly Controlled Modification of Object) or perhaps CWE-20 (Improper Input Validation) combined with an issue related to serialization/deserialization (No concatenation delimiter).
## Affected Systems
- Products: Wyvern Protocol (specifically Wyvern 2.2 smart contracts powering marketplaces like OpenSea)
- Versions: Wyvern 2.2 contracts (as reported in Q1 2022)
- Configurations: Listings/Offers where `calldata` mutation using `replacementPattern` was utilized, specifically affecting transfers that required the taker address to augment the `calldata`.
## Vulnerability Description
The Wyvern Protocol aggregates listing/offer parameters into a single commitment signed off-chain, reusing byte concatenation without delimiters (violating the Horton Principle: "mean what you sign and sign what you mean"). This ambiguity allows different sets of input parameters to result in the identical signed data hash if they result in the same concatenated byte sequence.
The critical application of this flaw was within the `calldata` parameter, which is mutatable during fulfillment via a `replacementPattern` bitmask (used, for example, by OpenSea to inject the offer taker's address). An attacker could use these bitwise modification primitives to shift the bits residing within the signed context, thereby changing the intended function selector (the first 4 bytes of `calldata`). Specifically, an attacker could shift the data to transform the intended selector (e.g., `transferFrom`) into a different, exploitable selector, such as `getApproved(uint)`.
## Exploitation
- Status: Not exploited in the wild (Vulnerability was reported and neutralized before malicious usage). A Proof of Concept (PoC) is not publicly detailed but implied by the technical description.
- Complexity: Medium (Requires knowledge of bitwise manipulation and precise alignment within the aggregated byte string and the 4-byte function selector). The text notes that exploiting the selector change reduced to roughly 1 in 64 offers being potentially exploitable based on address alignment.
- Attack Vector: Smart Contract Interaction (requires initiating a listing/offer interaction).
## Impact
- Confidentiality: Potential exposure if sensitive data was mishandled in the mutated call, though the primary impact is on Integrity/Availability.
- Integrity: **High**. An attacker could force the execution of a completely different function than the one intended by the signer. In the described scenario, an attacker could call `getApproved(0)` on behalf of the user, leading to the theft of WETH, even if the user had not approved the spender or still owned the NFT.
- Availability: Low direct impact, but asset loss results in complete loss of control over assets.
## Remediation
### Patches
- The vulnerability was neutralized in Q1 2022 by the Wyvern Protocol developers/OpenSea. Specific patch versions for the Wyvern 2.2 contract were not listed, but the issue stems from the underlying design of data aggregation/signing. Migration to newer protocols (like Seaport, mentioned elsewhere in the source material context) would resolve this.
### Workarounds
- No specific workarounds were detailed, as the vulnerability was patched internally following disclosure.
## Detection
- Indicators of compromise would involve atypical smart contract calls made immediately following a fulfillment transaction where the function selector deviates from the expected signature based on the original listing parameters and `replacementPattern`.
- Detection would involve static analysis of transaction traces examining the relationship between signed data commitments and the actual executed `calldata`, particularly looking for unexpected function selectors in fulfillment routines where `replacementPattern` was applied.
## References
- Vendor Advisories: OpenSea for Developers blog post: "Horton Hears A Who!" (Specific date implied Q1/Q2 2022 resolution).
- Relevant links - defanged: hxxps://paragraph.com/@sea-2/horton-hears-a-who