rustle
rustle copied to clipboard
A static analyzer for NEAR smart contract in Rust
Rustle
Rustle is an automatic static analyzer for NEAR smart contracts in Rust. It can help to locate tens of different vulnerabilities in NEAR smart contracts. According to DefiLlama, among the top 10 DApps in NEAR, 8 are audited by BlockSec. With rich audit experience and a deep understanding of NEAR protocol, we build this tool and share it with the community.
Get started
Prerequisite
Linux setup
Install the required toolkits with the following commands for Rustle in Linux. Commands are tested in Ubuntu 20.04 LTS.
# install Rust Toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# install LLVM 15
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" 15
# install Python toolchain
sudo apt install python3 python3-pip # requires python >= 3.8
pip3 install -r utils/requirements.txt # you need to clone this repo first
# add WASM target
rustup target add wasm32-unknown-unknown
# install other components
sudo apt install figlet
cargo install rustfilt
# [optional] useful tools for developing
LLVM_VERSION=
sudo apt install clangd-$LLVM_VERSION clang-format-$LLVM_VERSION clang-tidy-$LLVM_VERSION
macOS setup
The following commands are for users using macOS, they are tested only on Apple Silicon Mac, so use them with caution.
# install Rust Toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# install LLVM 15
brew install llvm@15
# install Python packages
pip3 install -r utils/requirements.txt # you need to clone this repo first
# using macOS default python3
# add WASM target
rustup target add wasm32-unknown-unknown
# install other components
brew install figlet coreutils gsed
cargo install rustfilt
Docker
We provide a docker solution.
# build the image
docker build --build-arg UID=`id -u` --build-arg GID=`id -g` -t rustle .
# run a container from the image
docker run --name rustle -it -v `pwd`:/rustle -w /rustle rustle bash
# exec the container
docker start rustle
docker exec -it -w /rustle rustle bash
Usage
./rustle [-t|--tg_dir <tg_dir>] [-d|--detector <detector_list>] [-o|--output <output_dir>] [-h|--help] <src_dir>
src_dir: Path to the contract source.tg_dir: Path to the contract build target. Defaults to be same assrc_dir.detector: The detector list. It can be used to pass multiple detectors or groups separated by,. Defaults toall.- pass
allgroup to enable all detectors. - pass
high,medium,lowandinfogroups to enable detector groups with different severity (refer to Detectors) - pass
nep-ft,nep-storageandnep-nftgroups to enable detectors implemented for specified NEP (refer to NEP detector groups) - pass detector ids in the table to enable those detectors
- pass
output: Path where audit reports will be generated in. Defaults to./audit-result.
Note: if the target bit code (.bc binary) built by cargo is not in the $src_dir, use -t|--tg_dir to set the target's directory, or it will be set to $src_dir by default.
The command below shows an example of analyzing the LiNEAR.
# clone LiNEAR
git clone https://github.com/linear-protocol/LiNEAR.git ~/near-repo/LiNEAR
# run Rustle
./rustle -t ~/near-repo/LiNEAR ~/near-repo/LiNEAR/contracts/linear
# [optional] run Rustle on specified detectors or severity groups and save audit reports in `~/linear-report`
./rustle -t ~/near-repo/LiNEAR ~/near-repo/LiNEAR/contracts/linear -d high,medium,complex-loop -o ~/linear-report
A CSV-format report will be generated in the directory "./audit-result".
Detectors
All vulnerabilities Rustle can find.
| Detector ID | Description | Severity |
|---|---|---|
unhandled-promise |
find Promises that are not handled |
High |
non-private-callback |
missing macro #[private] for callback functions |
High |
reentrancy |
find functions that are vulnerable to reentrancy attack | High |
unsafe-math |
lack of overflow check for arithmetic operation | High |
self-transfer |
missing check of sender != receiver |
High |
incorrect-json-type |
incorrect type used in parameters or return values | High |
unsaved-changes |
changes to collections are not saved | High |
nft-approval-check |
find nft_transfer without check of approval id |
High |
nft-owner-check |
find approve or revoke functions without owner check | High |
div-before-mul |
precision loss due to incorrect operation order | Medium |
round |
rounding without specifying ceil or floor | Medium |
lock-callback |
panic in callback function may lock contract | Medium |
yocto-attach |
no assert_one_yocto in privileged function |
Medium |
dup-collection-id |
duplicate id uses in collections | Medium |
unregistered-receiver |
no panic on unregistered transfer receivers | Medium |
nep${id}-interface |
find all unimplemented NEP interface | Medium |
prepaid-gas |
missing check of prepaid gas in ft_transfer_call |
Low |
non-callback-private |
macro #[private] used in non-callback function |
Low |
unused-ret |
function result not used or checked | Low |
upgrade-func |
no upgrade function in contract | Low |
tautology |
tautology used in conditional branch | Low |
storage-gas |
missing balance check for storage expansion | Low |
unclaimed-storage-fee |
missing balance check before storage unregister | Low |
inconsistency |
use of similar but slightly different symbol | Info |
timestamp |
find all uses of timestamp |
Info |
complex-loop |
find all loops with complex logic which may lead to DoS | Info |
ext-call |
find all cross-contract invocations | Info |
promise-result |
find all uses of promise result | Info |
transfer |
find all transfer actions | Info |
public-interface |
find all public interfaces | Info |
NEP detector groups
Apart from the groups by severity level, Rustle provides some detector groups by corresponding NEP. Currently, Rustle supports the following groups.
| NEP | Detector Group ID | Detector IDs |
|---|---|---|
| NEP-141 | nep-ft |
nep141-interface, self-transfer, unregistered-receiver |
| NEP-145 | nep-storage |
nep145-interface, unclaimed-storage-fee |
| NEP-171, NEP-178 | nep-nft |
nep171-interface, nft-approval-check, nft-owner-check |
Add new detectors
- Fork this repo to your account.
- Put the new detector under /detectors.
- Add a detection target in /Makefile with commands to run your detector.
- Add the target to the dependency of
audittarget and its name to detector list and severity groups in./rustlescript. - Add processing code in utils/audit.py (refer to other detectors' code in
audit.py). - Submit a pull request from your branch to the main.
Note
Rustle can be used in the development process to scan the NEAR smart contracts iteratively. This can save a lot of manual effort and mitigate part of potential issues. However, vulnerabilities in complex logic or related to semantics are still the limitation of Rustle. Locating complicated semantic issues requires the experts in BlockSec to conduct exhaustive and thorough reviews. Contact us for audit service.
License
This project is under the AGPLv3 License. See the LICENSE file for the full license text.