Vulnerabilities every beginner Smart Contract Security Researcher should find - Part 1
Discovering vulnerabilities is a crucial aspect of Smart Contracts. As a beginner in this field, it is essential to know which vulnerabilities to look for. This knowledge will empower you to identify and address security weaknesses effectively, ultimately contributing to the safety and success of blockchain technology.
That's why in this article, you will see vulnerabilities that are easy to learn and perfect for beginner Smart Contract Security Researchers.
Excess Ether does not return to the user
It is very important that when a user sends more ether than needed, the excess is returned to the user.
Take a look at this function as an example:
function passThruGate(uint index, address) override external payable {
uint price = getCost(index);
require(msg.value >= price, 'Please send more ETH');
......
......
......
if (msg.value > 0) {
(bool sent, bytes memory data) = gate.beneficiary.call{value: msg.value}("");
require(sent, 'ETH transfer failed');
}
}
If a user sends msg.value
more than needed, the remainder will be lost.
Missing check for active L2 Sequencer
Optimistic rollup protocols move all execution off the layer 1 (L1) Ethereum chain, complete execution on a layer 2 (L2) chain, and return the results of the L2 execution back to the L1. These protocols have a sequencer that executes and rolls up the L2 transactions by batching multiple transactions into a single transaction.
If a sequencer becomes unavailable, it is impossible to access read/write APIs that consumers are using and applications on the L2 network will be down for most users without interacting directly through the L1 optimistic rollup contracts. The L2 has not stopped, but it would be unfair to continue providing service on your applications when only a few users can use them.
To help your applications identify when the sequencer is unavailable, you can use a data feed that tracks the last known status of the sequencer at a given point in time. This helps you prevent mass liquidations by providing a grace period to allow customers to react to such an event.
No storage gap for upgradable contracts might lead to storage slot collision
For upgradeable contracts, there must be a storage gap to “allow developers to freely add new state variables in the future without compromising the storage compatibility with existing deployments”.
Otherwise, it may be very difficult to write new implementation code. Without a storage gap, the variable in the contract contract might be overwritten by the upgraded contract if new variables are added.
Some protocols have the incorrect assumption that all tokens have the same decimals
It is very important to check what tokens will be used by the protocol and always take into account how many decimals a token has when performing mathematical operations.
ECDSA signature malleability in OpenZeppelin contract versions lower than 4.7.3
OpenZeppelin has a vulnerability in versions lower than 4.7.3. The functions ECDSA.recover
and ECDSA.tryRecover
are vulnerable to a kind of signature malleability due to accepting EIP-2098 compact signatures in addition to the traditional 65 byte signature format. This is only an issue for the functions that take a single bytes
argument, and not the functions that take r, v, s
or r, vs
as separate arguments.
The potentially affected contracts are those that implement signature reuse or replay protection by marking the signature itself as used rather than the signed message or a nonce included in it. A user may take a signature that has already been submitted, submit it again in a different form, and bypass this protection.
Some ERC20 tokens deduct a fee on transfer
Some ERC20 token implementations have a fee that is charged on each token transfer. This means that the transferred amount isn't exactly what the receiver will get.
It is therefore important to take into account whether the token takes a charge on a given transfer. If it does then you need to compare balances pre/post transfer.
Some tokens must be approved by zero first
Some ERC20 tokens (like USDT) do not work when changing the allowance from an existing non-zero allowance value and they will revert when updating the allowance. They must first be approved by zero and then the actual allowance must be approved.
Use call()
instead of transfer()
when sending ETH
Using the transfer()
function on the address payable
is not recommended.
The transfer()
function forwards a fixed amount of 2300 gas. The gas cost of EVM instructions may change significantly during hard forks which may break already deployed contract systems that make fixed assumptions about gas costs.
The use of the deprecated transfer()
function when transferring ETH
will inevitably make the transaction fail when:
The claimer smart contract does not implement a payable function.
The claimer smart contract does implement a payable fallback which uses more than 2300 gas units.
The claimer smart contract implements a payable fallback function that needs less than 2300 gas units but is called through a proxy, raising the call's gas usage above 2300.
Additionally, using more than 2300 gas might be mandatory for some multi-sig wallets.
Missing deadline check when function performs a swap
Missing deadline checks allow pending transactions to be maliciously executed in the future. You need to add a deadline parameter to all functions that potentially perform a swap on the user's behalf.
Solmate SafeTransferLib doesn't check whether the ERC20 contract exists
The Solmate safeTransfer
and safeTransferFrom
don't check the existence of code at the token address.
This may lead to miscalculation of funds and may lead to loss of funds, because if safeTransfer()
and safeTransferFrom()
are called on a token address that doesn't have a contract in it, it will always return success, bypassing the return value check.
The security of your protocol is one of the most important things you need to ensure. If you want your protocol to be secured, send me a message on Twitter or Telegram
Subscribe to my newsletter
Read articles from Dimitar Tsvetanov directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Dimitar Tsvetanov
Dimitar Tsvetanov
Smart Contract Security Researcher