Full Report
Sei Network is a layer 1 blockchain built on Cosmos with some pretty crazy functionality. In particular, there are two execution runtimes for smart contracts in both EVM and CosmWasm. The EVM can run in parallel as well. In Cosmos, there is code that can run at the beginning or the end of a block, besides the regular transactions. If a Go panic occurs during either the begin or end blocker code, then it results in a chain halt. In Cosmos, some funds may not be spendable. This is because the tokens could be staked at that point. When calling SendCoinsAndWei() on a block specific account, the call used GetBalance() to get the amount of tokens to send. However, this includes the staked tokens, which cannot be transferred! How do we give it some funds that are staked? I didn't think it would be possible to force somebody to have unspendable tokens. However, using vesting accounts, it is! The author created a vesting account for the block specific address via vesting create-vesting-account in the Sei CLI. The balance calculation still sees these tokens but they cannot be spent, leading to a crash. To fix the issue, GetBalance() was simply changed to SpendableCoins. On top of that, they removed the panic just to be extra safe. The next bug is much more dangerous but I definitely enjoyed this first bug! While browsing the previous issues patch, they stumbled across the balance integration code for the EVM and Cosmos balances. They noticed that calling AddBalance() with a negative number would actually add the other users token to your balance. Armed with this knowledge, they decided to hunt for use cases with user controllable data on calls to Transfer(). They found three integration points: EVM opcodes, top level EVM message and CosmWasm integration. The integration between the two chains was the only unique aspect of this. By itself, the EVM module and CosmWasm module are known to be very safe. The internal message of a cross-environment call from CosmWasm to EVM was interesting now. The message MsgEVMTransaction allows for an amount to be set on it, which is a signed number! They quickly setup a Golang test to see if the transfer worked as expected... and it did! At this point, all funds are at risk on the chain. All you have to do is make a call to transfer funds to a user and you can steal all of their funds. Neat! To make matters worse, you could steal all of the funds then become a supermajority validator! Since the active validator set is recaculated at the end of each block (instead of a waiting period), this results in an instant compromise. At this point, you would be able to control the stake in a PoS blockchain to create funds out of thin air. Of course, this can be used to attack other chains over IBC as well. The end to end proof of concept is a fairly simple CosmWasm contract written in Rust that has a submessage for the EVM transfer. Pretty neat :) For the first bug, they got 75K. For the second bug, they got 2M. Overall, two awesome bugs that were complex enough to be missed in an audit but were both obvious red flags if somebody took the time to read the code. Amazing finds! An interesting aspect they mention at the beginning of the article was that the issue was slated for release but before it had actually be shipped. This feels like a good sweet spot time to report bugs and still be get paid out.
Analysis Summary
# Vulnerability: Critical Logic Flaws in Sei Network EVM/CosmWasm Integration
## CVE Details
- **CVE ID**: N/A (Discovered and patched pre-release)
- **CVSS Score**: 10.0 (Calculated estimate for Bug 2)
- **CWE**:
- CWE-680: Integer Overflow to Buffer Overrun (Negative/Signedness Issue)
- CWE-755: Improper Handling of Exceptional Conditions (Panic in ABCI)
## Affected Systems
- **Products**: Sei Network (Layer 1 Blockchain)
- **Versions**: Found in April 2024 (pre-production release candidate)
- **Configurations**: Systems integrating the EVM module with the Cosmos SDK and CosmWasm runtimes.
## Vulnerability Description
Two distinct vulnerabilities were identified:
1. **ABCI EndBlocker Panic (Availability)**: The `x/evm` module executed code at the end of every block to clear "coinbase addresses." The code used `GetBalance()` to retrieve total funds (locked + unlocked). However, only unlocked funds can be transferred via `SendCoinsAndWei()`. By using a vesting account to send locked tokens to a deterministic coinbase address, an attacker could force the `SendCoinsAndWei()` call to fail, triggering a Go `panic`. Since this occurs in an ABCI hook (outside the recovery loop), it results in a permanent chain halt.
2. **Negative Value Transfer (Integrity/Total Loss of Funds)**: The integration between CosmWasm and the EVM allowed for `MsgEVMTransaction` messages where the `amount` field was a **signed** integer. The internal `AddBalance()` logic did not properly validate against negative numbers. Calling a transfer with a negative value subtracted from the sender (adding to them) and added to the receiver (subtracting from them). This allowed an attacker to drain any account on the chain by "transferring" negative balances.
## Exploitation
- **Status**: PoC available. Reported via bug bounty; caught before shipping to production.
- **Complexity**: Low to Medium (Requires knowledge of deterministic address calculation and CosmWasm contract deployment).
- **Attack Vector**: Network (Sending a transaction/deploying a contract).
## Impact
- **Confidentiality**: None
- **Integrity**: **Critical**. Ability to steal all funds on the network ($5B+ FDV at risk) and achieve instant supermajority validator status.
- **Availability**: **Critical**. Ability to permanently halt the chain via a state machine panic.
## Remediation
### Patches
- **Bug 1**: `GetBalance()` was replaced with `SpendableCoins()` to ensure only transferable funds are calculated, and the `panic(err)` was removed to prevent chain halts.
- **Bug 2**: Validation was added to the EVM integration layer to ensure `amount` values in cross-environment calls cannot be negative.
### Workarounds
- No manual workarounds provided; these require protocol-level code changes.
## Detection
- **Indicators of Compromise**:
- Unusual vesting account creations targeting deterministic "coinbase" addresses (e.g., `sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqqlve8dv`).
- Transactions involving `MsgEVMTransaction` with negative value parameters.
- Massive, sudden shifts in balances for bonded token pools or validator stakes.
- **Detection Methods**: Monitor chain logs for `SendCoinsAndWei` errors or unexpected balance changes in the `x/bank` module.
## References
- **Vendor**: [https://www.sei.io/](https://www.sei.io/)
- **Researcher Report**: [https://usmannkhan.com/](https://usmannkhan.com/)
- **Cosmos SDK ABCI Security**: [https://github.com/crytic/building-secure-contracts/tree/master/not-so-smart-contracts/cosmos/abci_panic](https://github.com/crytic/building-secure-contracts/tree/master/not-so-smart-contracts/cosmos/abci_panic)