Signed/unsigned integer vulnerabilities
Improper handling of signed integers can allow attackers to exploit overflow/underflow conditions.Vulnerable code
Secure implementation
Sending sensitive data on-chain
The entire smart contract computation is transparent; confidential runtime values can be retrieved through emulation.Vulnerable code
Account destruction race conditions
Destroying accounts using send mode128 + 32 without proper checks can lead to fund loss in race conditions.
Vulnerable code
Secure approach
Missing replay protection
Replay protection is a security mechanism that prevents an attacker from reusing a previous message. External messages without replay protection can be re-executed multiple times by an attacker which could lead to fund loss or other undesired behavior.Secure implementation
Unconditional accepting of external messages
Incoming external messages do not transfer funds. Receiving smart contract must pay for their processing from its balance. Upon receiving an external message, a smart contract can spend some free gas (gas_credit) in order to decide whether it is ready to accept it, and then pay for its further processing.
External messages are usually accepted through the ACCEPT TVM instruction, which sets gas_limit to its maximum possible value specified in the network configuration, and sets gas_credit to zero. From this point on, the contract will have to pay for the entire processing of the incoming message.
Therefore, if ACCEPT is not guarded by a condition, an attacker might repeatedly send messages, and spend the entire balance of the contract.
The SETGASLIMIT instruction can lead to the same issue.
Vulnerable code
Secure implementation
Checks before accepting an external message vary by use case. The following example is a part of wallet v3 code, that doesn’t accept a message if it isn’t signed by the wallet’s owner.Invalid throw values
Exit codes0 and 1 indicate normal execution of the compute phase of the transaction. Execution can be unexpectedly aborted by calling a throw directly with exit codes 0 and 1. This can make debugging very difficult since such aborted execution would be indistinguishable from a normal one.
Gas limitation
Be careful with the Out of gas error. It cannot be handled, so try to pre-calculate the gas consumption whenever possible. This will help avoid wasting extra gas, as the transaction will fail anyway.Secure implementation
Insecure random numbers
Generating truly secure random numbers in TON is challenging. The built-in random functions are pseudo-random and depend on logical time. An attacker can predict the randomized number by brute-forcing the logical time in the current block.Secure approach
- For critical applications, avoid relying solely on on-chain solutions.
- Use built-in random functions with randomized logical time to enhance security by making predictions harder for attackers without access to a validator node. Note, however, that it is still not entirely foolproof.
- Consider using the commit-and-disclose scheme:
- Participants generate random numbers off-chain and send their hashes to the contract.
- Once all hashes are received, participants disclose their original numbers.
- Combine the disclosed numbers (e.g., summing them) to produce a secure random value.
- Don’t use randomization in external message receivers, as it remains vulnerable even with randomized logical time.
Executing third-party code
Executing untrusted code can compromise contract security.Prevention
Race condition of messages
A message cascade can be processed over many blocks. Assume that while one message flow is running, an attacker can initiate a second message flow in parallel. That is, if a property was checked at the beginning, such as whether the user has enough tokens, do not assume that it will still be satisfied at the third stage in the same contract.Preventing front-running with signature verification
In TON blockchain, all pending messages are publicly visible in the mempool. Front-running can occur when an attacker observes a pending transaction containing a valid signature and quickly submits their own transaction using the same signature before the original transaction is processed.Secure approach
Include critical parameters like the recipient address (to) within the data that is signed. This ensures that the signature is valid only for the intended operation and recipient, preventing attackers from reusing the signature for their benefit. Also, implement replay protection to prevent the same signed message from being used multiple times.
Vulnerable approach
Do not sign data without including essential context like the recipient address. An attacker could intercept the message, copy the signature, and replace the recipient address in their own transaction, effectively redirecting the intended action or funds.Return gas excesses carefully
If excess gas is not returned to the sender, funds accumulate in contracts over time. This is suboptimal. Add a function to rake out excess, but popular contracts like Jetton wallet return it to the sender with a message using the0xd53276db opcode.