Full Report
The Fuel Network ran an Immunefi contest for the entire network. From their custom VM to compilers to the bridge... lots of attack surface. The author of this post dove into the compiler and contract runtime. When contract A calls contract B, there is an ABI to preform type safety. The arguments are encoded into raw bytes in order to make the actual call in the contract. In the bytecode of the callee contract, there is implicit type information based upon the source code. One has compile time checks and the other has runtime verification on the values. In the EVM, extra data at the end or in the middle of a structure is ignored. If the type is completely incorrect (like a string where an integer should be), then it reverts. This is more a Solidity compiler added protection than an actual protection added by the VM. In Fuel, if an extra value is added to a struct it's not ignored - it corrupts the next value! For instance, if a struct only had a value called key with 32 bytes but we passed in an extra u8. The value of the u8 is just added to the next type instead of being ignored. All types keep their size but can be changed to unexpected values. I'm guessing that this corruption happening after the verification of the type but I'm not entirely sure from the post. Why is this useful? The boolean type is usually guaranteed to either be a 0 or a 1. Given that the compiler knows this, it will do checks in weird ways that may be bypassable. The author provides an if statement with two options: option == true and option == false without an else clause. Since a boolean value of 100 wouldn't fall into either of these, we can break logic that assumes a binary value for a boolean. An additional impact is that a boolean could be stored with a non-zero value in storage. This could cause a DoS when loading the value or cause more corruption as well. An interesting impact is that since this happened in the compiled code, all deployed code would have to be redeployed with a new version of the compiler. I'm slightly confused on why the corruption must happen. From my end, it appears that we could just make a boolean any value. My guess is that there is verification in the compiled code that happens first then the decoding happens that corrupts the values. Interesting bug and thanks for sharing!
Analysis Summary
# Vulnerability: Logic Bypass via ABI Decoding Memory Corruption in FuelVM
## CVE Details
- **CVE ID**: N/A (Discovered via Immunefi Attackathon)
- **CVSS Score**: 9.0 - 10.0 (Critical)
- **CWE**: CWE-20: Improper Input Validation / CWE-119: Memory Corruption
## Affected Systems
- **Products**: Fuel Network (FuelVM), Sway Compiler (`forc`).
- **Versions**: All versions prior to the Mainnet launch (Beta-5 and earlier).
- **Configurations**: Contracts performing cross-contract calls using the Sway ABI where structs or complex types are passed as arguments.
## Vulnerability Description
The vulnerability exists in how the FuelVM and Sway-compiled contracts handle ABI (Application Binary Interface) decoding. When Contract A calls Contract B, the arguments are encoded into raw bytes.
In Fuel, the decoding process failed to strictly enforce bounds or ignore unexpected padding/extra data within structured types. If a caller provided more data than a struct expected (e.g., adding an extra byte to a 32-byte field), the extra data was not discarded. Instead, it "overflowed" and corrupted the memory space of the subsequent variable or type.
This is particularly critical for **boolean types**. In Sway/FuelVM, a boolean is expected to be strictly `0` (false) or `1` (true). By using this corruption primitive, an attacker could force a boolean to hold an unexpected value (e.g., `100`). If a contract uses binary logic (e.g., `if (val == true) { ... } else if (val == false) { ... }`), a corrupted boolean bypasses both conditions, potentially skipping critical security checks or state updates.
## Exploitation
- **Status**: PoC available (demonstrated during Immunefi Attackathon). No known exploitation in the wild.
- **Complexity**: Medium (Requires understanding of Fuel's memory layout and ABI encoding).
- **Attack Vector**: Network (Remote execution via smart contract interaction).
## Impact
- **Confidentiality**: Low
- **Integrity**: Critical (Complete bypass of contract logic and potential corruption of on-chain state/storage).
- **Availability**: High (Can lead to Denial of Service if corrupted values cause the VM to revert during state loading).
## Remediation
### Patches
- The Fuel Network team has updated the Sway compiler and the underlying VM logic to ensure strict ABI decoding.
- **Recommendation**: Developers must recompile all smart contracts using the latest version of the Sway toolchain (`forc`) and redeploy them to the latest network iteration.
### Workarounds
- Implement manual validation for boolean values (e.g., `require(val == true || val == false)`) at the start of functions, though this is not a substitute for a compiler-level fix.
## Detection
- **Indicators of Compromise**: Transactions that successfully call functions but appear to skip logic branches that should be mathematically exhaustive.
- **Detection Methods**: Static analysis of compiled bytecode for non-standard boolean comparisons and fuzzing ABI inputs with "over-packed" data structures.
## References
- [h]ttps://github.com/minato7namikazi/Fuel-Blockchain-Critical-Vulnerability
- [h]ttps://immunefi.com/bug-bounty/fuel/
- [h]ttps://fuel.network/