A minimal, universal JSON-RPC fuzzer for testing Sui nodes and other RPC endpoints.
- Python 3.8+
- requests library:
pip install requests - Running Sui devnet (local only—do not fuzz mainnet)
sui client start --local
# Or follow Sui docs to run a local validator clusterVerify RPC endpoint is reachable:
curl -s http://127.0.0.1:9000 | jq . chmod +x run.sh
./run.shrun.sh does the following automatically:
- checks Python +
requests - checks Sui CLI presence (prebuilt binary/package only; no source build)
- starts local Sui devnet if RPC is not up
- runs conservative fuzzing and prints summary results
python3 fuzz_proto.py \
--url http://127.0.0.1:9000 \
--method sui_executeTransaction \
--template template.json \
--workers 6 \
--iterations 500 \
--delay 0.02python3 fuzz_proto.py \
--url http://127.0.0.1:9000 \
--method sui_getObject \
--template template.json \
--workers 2 \
--iterations 100 \
--delay 0.05--url: Target RPC endpoint--method: JSON-RPC method name (e.g.,sui_executeTransaction,sui_getObject,sui_getTransaction)--template: Path to JSON payload template--workers: Concurrent threads (default: 6)--iterations: Iterations per worker (default: 500)--delay: Seconds between requests per worker (default: 0.02)--timeout: HTTP timeout in seconds (default: 5.0)--outdir: Output directory for findings (default:fuzz_findings)--rpc_mode: Wrap payload as JSON-RPC (disabled by default, enable explicitly)--wrap_params_array: Wrap params in array for JSON-RPC (disabled by default, enable explicitly)
While fuzzing, tail your node logs:
journalctl -u sui-node -f
# Or: docker logs -f <container_name>Watch for:
- Panics
- Crashes
- 5xx errors
- Memory leaks
Findings are saved to fuzz_findings/:
findings_summary.json: Aggregated list of all findingsfinding-{uuid}.json: Individual reproducer seeds
Each entry contains:
{
"id": "<uuid>",
"worker": 0,
"iter": 42,
"status": 500,
"response_snippet": "...",
"request": { /* the fuzzing payload that triggered the issue */ }
}To replay a finding:
curl -X POST http://127.0.0.1:9000 \
-H "Content-Type: application/json" \
-d @fuzz_findings/finding-<uuid>.jsonOr programmatically with the request field from the JSON.
Edit template.json to match your RPC method's expected params structure.
Examples:
{
"id": "0x1"
}{
"digest": "0x0000000000000000000000000000000000000000000000000000000000000000"
}{
"tx_bytes": "0x",
"sig_scheme": "Ed25519",
"signature": "0x00",
"sender": "0x1",
"gas_budget": 1000,
"gas_price": 1
}⚠️ Use local/devnet only. Do not fuzz public mainnet nodes.- Install Sui CLI from an official prebuilt release/package before running
run.sh. run.shintentionally does not build Sui from source, so startup remains fast.- Start with low rates (
--workers 2 --iterations 100 --delay 0.05) and increase after confirming safety. - Prefer read-only methods (
sui_getObject,sui_getTransaction) first. sui_executeTransactionrequires valid signatures and may cause state changes—test carefully.- Respect rate limits and bug-bounty program rules.
- Schema-aware mutations: Intelligent payload morphing
- Concurrent fuzzing: Multi-threaded request generation
- Automatic crash detection: Flags 5xx responses and panics
- Reproducible findings: Saves seed payloads for each crash
- Generic JSON-RPC wrapper: Works with any JSON-RPC endpoint
- JSON Schema support for generates valid-ish payloads
- gRPC/Protobuf adapter
- Corpus/seeding and AFL-style mutation integration
- Automatic state-root comparison across nodes