Bybit recently suffered a hacker attack involving $150 million, which has attracted widespread attention from the BlockTempo community. The hackers successfully penetrated Bybit's multi-signature cold wallet and, through some means, altered or exploited the existing security mechanisms to transfer large amounts of assets to unknown addresses.
This attack not only caused Bybit huge financial losses, but also posed new challenges to the security of multi-signature wallets. This article, written by a BSOS Labs blockchain security researcher, will delve into the technical details of the attack, including Bybit's multi-signature architecture, the attacker's tactics, and the security implications of this incident.
Event Background
Multisignature Wallet
In the Ethereum blockchain design, there are two types of accounts: EOA (Externally Owned Account) and Contract Account. Bybit's multi-signature cold wallet involved in this incident belongs to the latter. This wallet is actually a smart contract that defines some business logic through programming. In the design of a multi-signature account, when this wallet receives assets from the outside, if it wants to withdraw or perform any operational activities, it must pass the thresholds set by this multi-signature wallet in order to actually execute.
General users can imagine the Safe Wallet as a company's vault, and this vault is jointly managed by the company's directors. When the company directors want to withdraw assets from the vault or use these assets for external investment, they must go through the following process:
- The board of directors first proposes, deciding the amount of funds to be used, the target, and the operations to be performed
- The members of the board of directors sign the proposal, and when the number of signers exceeds the threshold, the proposal can be actually executed
For example, in a 5-out-of-3 multi-signature wallet, there are a total of 5 directors, called Signers. These Signers can first initiate a proposal, and the term corresponding to the multi-signature wallet is Transaction, or some call it Proposal, to avoid confusion with the blockchain's transaction.
This proposal can be a simple transfer of ETH/ERC-20 to other accounts, or it can be more complex DeFi operations. Then these Signers will sign the Proposals, indicating their agreement with this proposal. During this process, a Signature will be generated as a certificate. When the number of valid Signatures exceeds 3, the user can call the executeTransaction operation of the Safe Wallet and submit these Signatures. After verifying that these Signatures are indeed signed by the authenticated Signers, i.e., the directors of the vault, the original Proposal content will be executed.

The simple process is shown in the above figure. First, Signer 0 submits a Proposal, then Signer 2 and Signer 3 confirm that the Proposal has no issues and sign it. Usually, the person who submits the Proposal will also sign it at the same time, so at this point, 3 signatures have been obtained, meeting the threshold set by this multi-signature wallet. Then the content of this Proposal can be executed. In the design of the Safe frontend, if you sign at the time when the threshold is just met, the system will ask you whether to sign and execute together. You can choose Yes, or choose No and let others execute it for you, the difference is who will pay the gas fee.
Proxy Pattern
The above has introduced the operation of the multi-signature wallet through the Safe Wallet. Let's then look at the contract design of Safe. The logic mentioned above is largely written in the smart contract of this wallet. If you are interested, you can refer to the main contract implementation of the Safe Wallet: https://etherscan.io/address/0x34cfac646f301356faa8b21e94227e3583fe3f5f#code
This contract is not complicated, and the amount of code is not very large, but if a Safe wallet has to be deployed every time it is created, it would consume a lot of Gas, so Safe uses the Proxy Pattern to reduce costs. It's important to note that this is the Proxy Pattern, not the Upgradeable Proxy, which is different from the common Transparent Proxy and UUPS Proxy, as there is no preset upgrade behavior here. The specific working principle is more like the Minimal Proxy in EIP-1167.

When a user creates a Safe wallet, a Proxy will be created, and this Proxy's code is very simple, basically just using Delegatecall to call the main contract, and the data used is the data when the user interacts with the Proxy. All the business logic is in the main contract 0x34Cf…3F5F, but due to the characteristics of Delegatecall, the state (such as token balance, etc.) of each Proxy is separated, as shown in the figure above. This design does not cause everyone's assets to be mixed together due to a single main contract.
In simple terms, this Proxy calls the main contract through Delegatecall, using the business logic of the main contract to modify the state of the Proxy itself, such as token transfer operations.
In the Bybit incident, there were also two addresses, one for the Proxy and one for the main contract, both on the Ethereum mainnet.
- Proxy: 0x1Db92e2EeBC8E0c075a02BeA49a2935BcD2dFCF4
- Safe Wallet: 0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F
We will now take a closer look at the code of this Proxy. You will find a variable called masterCopy
(L#14), which is set once during the contract creation (see the contract's Constructor
, L#18). The initial value of this variable is the main contract 0x34Cf…3F5F, and the function()
(L#26) will pass all the user-supplied data through the delegatecall
(L#39) assembly block to the main contract.
NOTE: Readers familiar with Solidity may find the function()
a bit unfamiliar, but this is actually the fallback
function in Solidity 0.5.0.
Let's take a look at the implementation of the main contract's execTransaction
function. This function takes many parameters, but the most important ones are:
to
: the address of the contract to interact withvalue
: the amount of ETH to be sentdata
: the data to be sent when callingto
operation
: the mode of operation, supportingcall
anddelegatecall
in theSafe
signature
: the signature of eachSigner
Let's briefly explain the workflow:
- L#25–32 use
encodeTransactionData
andkeccak256
to reconstruct the Digest that the Signer signed - L#33 verifies that the Signature is from one of the multisig's Signers and that the Threshold is met
- L#40 actually executes the Transaction data, using low-level
call
ordelegatecall
If the Operation is 0, the logic is roughly as follows:
(bool success, ) = to.call{gas: gas}(data);require(success, "transaction execution failed");
Attack Transaction
So what is the connection between this attack and the above? According to the Bybit CEO, when they signed the multisig wallet Proposal, they wanted to transfer some assets from the cold wallet to the hot wallet, which was a routine asset transfer. They checked the Safe wallet website and the transfer address information, and they fully reviewed the Proposal before signing and executing it.
However, when examining the actual executed Transaction, some strange things can be found. The following is a snippet of the parameters when this Transaction was executed, where you can see that the value is 0, and the data is not a null value. According to our previous discussion, the value should be the amount of ETH to be transferred, but here it is 0. A regular ETH transfer would not require any data.
If it's not an ETH transfer, but a transfer of WETH or stETH, for example, then a value of 0 and non-null data would be reasonable. By parsing the first 4 bytes of the data, which represent the function selector, we can try to understand what operation the data is trying to execute.

Throwing 0xa9059cbb
into the function signature database, we can find that ID 145 is the function selector for the ERC-20 transfer
operation.

And decoding the rest of the data, the parameters match the ERC-20 Transfer, with to
(address) and amount
(uint256). So the attack is well disguised, and without carefully checking the data, one might be fooled by the function selector.

But the strange thing is that if it's just an ETH/ERC-20 transfer, we could have used call
(Operation = 0) to execute it. However, the Operation value here is 1 (see Figure 3), indicating that delegatecall
was used. Combining our understanding of the Proxy Pattern, this operation is equivalent to the Proxy contract using the logic of the to
contract (0x9622…C7242) to modify the Proxy's own state.
By observing the 0x9622…C7242 contract with tools like Dedaub, we can see that this contract has a transfer
operation (L#15) that has nothing to do with ERC-20 Transfer. It simply assigns the recipient
parameter to the _transfer
variable (L#07).

For convenience, let's call the 0x9622…C7242 address the Malicious Contract. Why is it setting the _transfer
value to the recipient
parameter? Let's break down the entire workflow:
- After the Signer signs the operation, the Safe will call
execTransaction
on the Proxy contract - This operation will be forwarded to the Safe's main contract via
Delegatecall
, executing theexecTransaction
logic - In the
execTransaction
logic, it will call theto
address usingDelegatecall
, triggering thetransfer
operation, which modifies the_transfer
value
Simplifying this series of Delegatecall
s, the current operation is the Proxy using the logic of the Malicious Contract to modify the Proxy's own state. Since the _transfer
variable modified in the Malicious Contract is at Storage Layout Slot 0, the corresponding change will be to the Proxy contract's Storage Layout Slot 0. According to Figure 3, this value is the MasterCopy
.

The flow chart above also aligns with the invocation flow presented in Phalcon.

After the MasterCopy
is modified, future calls to the Proxy contract will no longer execute Delegatecall
to the Safe's main contract, but to the 0xbDd0…9516 address, which is the passed-in recipient
address.

Continuing to reverse the 0xbDd0…9516 contract, we can see two operations, one of which is the sweepETH function. At L#18, a call is executed to transfer ETH to the receiver's address.

And SweepERC20, at L#35 we can see that this is doing an ERC-20 Transfer, which will transfer all the Balance in the contract in one transaction.

So the reason why Bybit's internal accidental update of the MasterCopy address in the execTransaction led to the subsequent sweepERC20 and sweepETH operations is that these Transactions are the real operations that transfer the assets.

Blind Signing
So, is the root cause of this incident that Bybit did not check the values of the Safe when signing the multi-signature wallet? If the Operation value and other key address information in the parameters had been verified at that time, could the abnormal operation have been identified early and this attack prevented?
There are still many unanswered questions in this case. First, who initiated the multi-signature proposal? Did the other Signers carefully check the content of the proposal, including the Safe front-end URL and other important information? Is it possible that a Signer's private key has been compromised, putting the entire system at serious risk?
According to Bybit, its co-founder and CEO Ben did check the Safe's URL and actual parameter information during the signing process. However, the cold wallet signing displayed a string of gibberish, which may mean that the Safe's front-end website has been tampered with by hackers. Currently, Safe has temporarily shut down its front-end service to further clarify the course of events.
Another possibility is that Bybit's computer was hacked, causing the displayed screen to be a carefully forged page by the hacker, rather than the official Safe interface. This is not impossible, as a similar attack method occurred in the Radiant Capital incident in October 2024: Radiant Post-Mortem.
Radiant also used Safe's multi-signature wallet, and at the time, three senior engineers used hardware cold wallets for signing, and before signing, they used Tenderly to simulate the results of the Transaction and checked it strictly according to internal SOP. However, during the signing and execution process, MetaMask popped up an error message requesting re-signing.
This situation is not uncommon, as failures during Transaction execution due to Nonce or Gas-related issues often require re-execution. However, precisely because such operations are so common, when the wallet prompts a re-signing request, the engineers did not re-verify the specific content of the Transaction, and ultimately fell into the hacker's trap.
So how should we prevent this? Or are these attacks unstoppable?
In fact, in these incidents, the North Korean hackers are still mainly exploiting human weaknesses. We may unconsciously think that we are already very familiar with these operations, and thus easily fall into the trap.
To reduce the risk, we can isolate the operating environment of the multi-signature wallet from other devices, and ensure that we can carefully verify the Payload every time we sign. If any anomalies are found between Safe and Ledger, operations should be immediately stopped and the private key securely stored.
Establishing a certain SOP process and strictly following it every time, ensuring that each stage meets the specifications, can still effectively prevent the occurrence of such incidents.
Conclusion
Although the Web3 industry has been overshadowed by the Bybit incident, with a lingering impression of insufficient security and high risk, I believe that behind these frequent incidents, it will make everyone more aware of the importance of Operation Security, and the education and awareness of private key management and signing will be further deepened.
Looking back, from 2021 to 2023, hacker incidents occurred frequently, with multi-million dollar losses from smart contract vulnerabilities occurring every few weeks, but this has also gradually made the industry more aware of the importance of secure development and auditing, and the Bug Bounty system has become more clear. The monitoring systems deployed after actual deployment have also become more sophisticated.

Therefore, at the end of the article, we can take a relatively optimistic view of the future development of the industry. These seemingly simple but causing major losses incidents will gradually decrease as the industry matures, and the losses will also decrease accordingly.
This article was written by a blockchain security researcher from BSOS Labs, who holds a bachelor's degree and a master's degree from the Department of Computer Science and Information Engineering at National Taiwan University, and has participated in security research and contributions at DeFiHackLabs and smart contract development at Ocean Finance, and also serves as a lecturer in the field of blockchain security bootcamp.