Kelp DAO’s LRTOracle on Ethereum was unpaused on 2026-05-15 at block 25101232 by a Gnosis Safe transaction, not by an exploit transaction. The observed action is an authorized administrative state change: the Safe 0xb3696a817d01c8623e66d156b6798291fa10a46d executed LRTOracle.unpause() and the oracle implementation verified that the Safe held DEFAULT_ADMIN_ROLE in the protocol’s role manager before clearing the pause flag. No ERC-20 transfers, ETH transfers, approvals, flash loans, or attacker gains appear in funds_flow.json, so the financial impact of this transaction is 0. The alert source flagged the transaction because the contract changed from paused to unpaused, but the fetched artifacts do not support an exploit or unauthorized-access narrative for this tx.
Root Cause
Vulnerable Contract
No vulnerable contract is evidenced by this transaction. The target contract is LRTOracle proxy 0x349a73444b1a310bae67ef67973022020d70020d, which delegatecalls implementation 0xc59110239240761ccd3e670288443316e10dd271. The proxy relationship is confirmed both by the trace’s DELEGATECALL from proxy to implementation and by the manifest’s resolved EIP-1967 implementation metadata. Source type for both oracle and role-manager implementations is verified Solidity.
Vulnerable Function
No vulnerable function is evidenced by this transaction. The only privileged state-changing function executed on the target side is unpause(), full signature unpause(), selector 0x3f4ba83a, in 0xc59110239240761ccd3e670288443316e10dd271/contracts/LRTOracle.sol.
Vulnerable Code
The executed code path is an authorization check, not a flaw. The relevant verified code is:
function unpause() external whenPaused onlyLRTAdmin {
paused = false;
emit Unpaused(msg.sender);
}
and the admin-role modifier it depends on is:
modifier onlyLRTAdmin() {
if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.DEFAULT_ADMIN_ROLE, msg.sender)) {
revert ILRTConfig.CallerNotLRTConfigAdmin();
}
_;
}
Why It’s Vulnerable
It is not vulnerable based on the fetched evidence for this transaction.
Expected behavior: when the oracle is paused, only an account with DEFAULT_ADMIN_ROLE in the Kelp DAO role manager should be able to call unpause() and clear the pause flag.
Actual behavior: the trace shows exactly that path. LRTOracle.unpause() performs a STATICCALL to RoleManager.hasRole(bytes32,address) with role 0x00...00 and caller 0xb3696a817d01c8623e66d156b6798291fa10a46d, then completes successfully and emits Unpaused(msg.sender). The funds_flow.json artifact shows no value transfer side effects, so there is no evidence of an exploit payload hidden behind this Safe transaction.
Normal flow: a Safe submits a multisig-approved maintenance transaction that changes only pause state. Attack flow: not observed in the fetched artifacts.
Attack Execution
High-Level Flow
- An EOA submitted a transaction to Kelp DAO’s Safe.
- The Safe verified a bundle of owner signatures through repeated
ecrecoverprecompile checks. - The Safe executed a single downstream call to
LRTOracle.unpause(). - The oracle implementation checked whether the Safe held
DEFAULT_ADMIN_ROLEin the role manager. - The check passed, the oracle cleared its
pausedflag, and the Safe emitted a success event.
Detailed Call Trace
0x51c59785639cca31c09d0833749e76a5d945c9f3->0xb3696a817d01c8623e66d156b6798291fa10a46d,execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)(0x6a761202),CALL, value0.0xb3696a817d01c8623e66d156b6798291fa10a46d->0xd9db270c1b5e3bd161e8c8503c55ceabee709552, same selector,DELEGATECALL, value0.0xb3696a817d01c8623e66d156b6798291fa10a46d-> precompile0x0000000000000000000000000000000000000001, unresolved selector0x161a4fd5,STATICCALL, repeated six times for signature recovery / validation.0xb3696a817d01c8623e66d156b6798291fa10a46d->0x349a73444b1a310bae67ef67973022020d70020d,unpause()(0x3f4ba83a),CALL, value0.0x349a73444b1a310bae67ef67973022020d70020d->0xc59110239240761ccd3e670288443316e10dd271,unpause()(0x3f4ba83a),DELEGATECALL, value0.0x349a73444b1a310bae67ef67973022020d70020d->0x947cb49334e6571ccbfef1f1f1178d8469d65ec7,hasRole(bytes32,address)(0x91d14854),STATICCALL, value0.0x947cb49334e6571ccbfef1f1f1178d8469d65ec7->0xd4f475a7df199b3106f622a3a825ff399d4dafce,hasRole(bytes32,address)(0x91d14854),DELEGATECALL, value0.
All resolved selectors above match local verification: cast sig "execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)" = 0x6a761202, cast sig "unpause()" = 0x3f4ba83a, and cast sig "hasRole(bytes32,address)" = 0x91d14854.
Financial Impact
funds_flow.json is empty for token transfers, ETH transfers, and approvals, and its summary is No attacker gains detected. There is therefore no token loss, no ETH loss, no flash-loan principal movement, and no attacker profit attributable to this transaction.
The transaction’s economic effect is limited to gas paid by the submitting EOA. At the protocol level, the only evidenced state change is that LRTOracle moved from paused to unpaused. Whether later transactions abused the newly unpaused state is outside the scope of this single-tx artifact set and is not evidenced here.
Evidence
- Transaction hash:
0xb1bd0cfcf28310fe36ee74b1ec63464610d82406a183eaf42e0defe1ea0c21a1 - Chain: Ethereum mainnet
- Block number:
25101232 - Block timestamp:
2026-05-15T14:45:35Z - Receipt status:
0x1 - Tx sender EOA:
0x51c59785639cca31c09d0833749e76a5d945c9f3 - Safe executor:
0xb3696a817d01c8623e66d156b6798291fa10a46d - Target proxy:
0x349a73444b1a310bae67ef67973022020d70020d - Target implementation:
0xc59110239240761ccd3e670288443316e10dd271 - Role manager proxy:
0x947cb49334e6571ccbfef1f1f1178d8469d65ec7 - Role manager implementation:
0xd4f475a7df199b3106f622a3a825ff399d4dafce - Receipt log
0x1f6:LRTOracleemittedUnpaused(address)withmsg.sender = 0xb3696a817d01c8623e66d156b6798291fa10a46d - Receipt log
0x1f7: the Safe emittedExecutionSuccess(bytes32,uint256), confirming successful multisig execution - Source check:
unpause()is guarded bywhenPausedandonlyLRTAdminin verifiedLRTOracle.sol - Trace check: the only downstream application call after Safe signature verification is
unpause() - Funds-flow check: no transfers, approvals, net changes, or attacker gains were detected
- Prestate check:
trace_prestateTracer.jsonrecords oracle storage changes consistent with a pause-flag update and no balance movement on the oracle