Reproduced Exploit
Panoptic: BuilderWallet init() is unprotected and re-initializable
Chain
Other
Category
untagged
Date
Jan 1970
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: RiskEngine.sol#. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/logic
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable code is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
BuilderWallet.init() has no access control and no only-once guard, so an attacker re-calls init(attacker) to overwrite builderAdmin, then passes sweep()'s msg.sender==builderAdmin check and transfers out the wallet's entire ERC20 balance - draining 500e18 of protocol-distributed builder fees to the attacker.
function init(address _builderAdmin) external { // @> VULN (this line)
Why it's exploitable here#
BuilderWallet.init() has no access control and no only-once guard, so an attacker re-calls init(attacker) to overwrite builderAdmin, then passes sweep()'s msg.sender==builderAdmin check and transfers out the wallet's entire ERC20 balance - draining 500e18 of protocol-distributed builder fees to the attacker.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0x671d353a77…:
- L68 — Vulnerable line: Executes
bool ok = IERC20(token).transfer(to, bal); - L69 — Step: Executes
if (!ok) { - L71 — Step: Executes
revert Errors.TransferFailed(token, address(this), bal, bal); - L79 — Step: Executes
string public name = 'Panoptic Builder Fee Token'; - L82 — Step: Executes
uint256 public totalSupply; - L84 — Step: Executes
mapping(address => mapping(address => uint256)) public allowance;
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test):
cd 65025-h-01-builderwallet-init-is-unprotectedre-initializable-enabl_exp
forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm. Both gates are green (registry forge test PASS + Playground _verify-poc VERDICT: PASS).
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: RiskEngine.sol#.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Panoptic: BuilderWallet init() is unprotected and re-initializable".
- Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.