Case: Radiant Capital Multisig Compromise (October 2024)
“This is the case study that proves a perfect contract audit is no longer enough. Radiant’s smart contracts behaved exactly as written. The Gnosis Safe behaved exactly as written. The Ledger hardware wallets behaved exactly as written. And yet $50M+ left the protocol because the bytes the signers thought they were signing were not the bytes the device hashed. Every auditor who only reads Solidity should read this case until they internalize that the signer’s machine is part of the threat model — and that ‘hardware wallet’ without ‘clear signing’ is a brand, not a defense.”
Tags: case-study multisig safe wallet-security malware dprk lazarus unc4736 clear-signing blind-signing operational-security #2024 Related: Tuan-12-Wallet-AA-Key-Management · Tuan-14-Governance-DAO-Security · Tuan-13-Frontend-dApp-Infrastructure · Case-Parity-Multisig-2017 · Case-BadgerDAO-Frontend-2021 · Case-Ronin-Bridge-2022
1. At a Glance
| Field | Value |
|---|---|
| Date | October 16, 2024 (attack tx ~21:24 UTC; ownership transfer executed mid-routine emissions adjustment) [verify timestamp against Etherscan / Arbiscan] |
| Protocol | Radiant Capital — a cross-chain (Arbitrum + BNB Chain + Ethereum + Base) over-collateralized lending market forked from Aave v2 / v3, with native cross-chain messaging via LayerZero and an omnichain reward token (RDNT). |
| Loss | **~50M–$58M depending on snapshot and asset prices at drain time) [verify exact split — Halborn / Mandiant / Radiant post-mortem all give slightly different numbers] |
| Funds-at-risk total | Radiant’s TVL at the time was on the order of $300M+ [verify]. The drain was bounded by what the freshly-installed owner could pull through transferOwnership-then-upgrade primitives, not by total TVL — the attacker drained what they could before the team paused. |
| Attack class | Multisig-signer compromise via malware-mediated transaction substitution. Not a contract bug. Not a key extraction. Signers’ machines displayed a routine, audited transaction in the Safe UI while transmitting an entirely different transaction to their hardware wallets, which then blind-signed the malicious payload. |
| Threshold compromised | 3-of-11 Safe; three signer machines were independently malware-implanted over weeks/months. On the day of the drain, all three signed the malicious payload believing it was a routine emissions / cap parameter adjustment. [verify 3-of-11 — Radiant’s post-mortem and Halborn both reference this; some sources say 3-of-10] |
| Root cause | A stack of operational failures: (1) low threshold relative to value at stake; (2) signer devices were ordinary developer machines (malware-rich); (3) hardware wallets in use did not clear-sign Safe execTransaction calldata — signers were effectively blind-signing arbitrary bytes; (4) no out-of-band Safe-tx-hash verification on a second device; (5) routine ownership-affecting calls were not differentiated in process from routine parameter changes. |
| Attribution | UNC4736, a DPRK-linked threat cluster tracked by Mandiant (Google Cloud) and overlapping with what other vendors call AppleJeus / part of the broader Lazarus Group constellation. Same actor cluster linked to multiple 2023–2024 DeFi key-compromise incidents. [verify Mandiant attribution wording] |
| Outcome | Attacker received contract ownership; immediately drained user-deposited assets across multiple chains; protocol paused; partial recovery via OFAC sanctions / centralized stablecoin freezes was limited because much of the loot was bridged out within hours. |
| Funds recovered | Minimal direct recovery [verify]. The attacker laundered through standard DPRK rinse pipelines (Tornado-equivalent mixers, cross-chain bridges, eventual conversion via OTC). |
| Lasting consequence | The case redefined “multisig security” for the industry. Post-Radiant: clear-signing of Safe transactions on hardware wallets became a checklist item; dedicated air-gapped signing machines became a recommended baseline for high-value Safes; the auditor’s deliverable for any protocol with a treasury multisig now includes a signer-side operational review, not just a contract review. |
2. Background
2.1 What Radiant Capital was
Radiant Capital launched in mid-2022 as a cross-chain money market. The pitch was simple and timely:
- Aave-style lending on multiple chains (initially Arbitrum, then BNB Chain, then Ethereum mainnet, then Base) [verify chain rollout order].
- Omnichain RDNT token using LayerZero’s OFT standard, so a holder on Arbitrum and a holder on BNB Chain held shares in the same protocol.
- dLP (dynamic liquidity provision) — users had to lock RDNT/ETH LP tokens to earn boosted lending rewards, creating a sticky-liquidity flywheel that goosed TVL early on.
At its peak (early 2024), Radiant claimed >300M [verify] amid the broader DeFi yield-product slowdown — still a significant target.
The protocol’s smart-contract surface was a relatively faithful fork of Aave v2/v3 plus LayerZero adapters and a custom RDNT-emissions/locking module. Halborn and BlockSec had audited the contracts. There is no public claim that the audit firms missed a Solidity-level bug in the relevant code path — and the post-mortem confirms this: the contracts behaved exactly as designed. The compromise was upstream of Solidity.
2.2 The multisig — the actual attack surface
Like virtually every Aave-fork lending protocol, Radiant’s contract suite had an owner: a Gnosis Safe with the power to call transferOwnership(...), upgrade implementations behind proxies, set reserve parameters, and pause markets. This Safe was the PoolAddressesProvider owner (and owner of related admin modules) — i.e., functionally the protocol’s god-mode account.
Configuration on the day of the attack [verify all numbers]:
- Safe threshold: 3
- Safe owners: 11
- Owner devices: a mix of personal MacBooks and dedicated signing machines, with Ledger Nano-series hardware wallets used for signing
- Signing UX: standard Safe Wallet web UI (
app.safe.globalor its at-the-time equivalent), Ledger connected via Ledger Live / Connect Kit - Approval workflow: signers reviewed the human-readable description in the Safe UI, clicked “Sign”, confirmed on Ledger; Ledger displayed
execTransactionparameters in raw hex because Ledger did not (and at the time of writing largely still does not) have native clear-signing rendering for SafeexecTransactioncalldata
That last bullet is the entire incident in one line. The signers were blind-signing.
2.3 The routine that wasn’t
On October 16, 2024, the operations team prepared what they understood to be a routine emissions / reserve-parameter adjustment transaction in the Safe UI. This kind of transaction was a regular occurrence — adjusting interest-rate curves, RDNT emission weights, supply caps. The signers were familiar with the shape; they had signed similar transactions many times. The Safe UI showed them what they expected to see: target contract, function name, parameters.
What was actually broadcast to each compromised signer’s Ledger was a different transaction: one that re-pointed protocol ownership to an attacker-controlled address. The Ledger displayed the unfamiliar execTransaction calldata as a long hex blob (the device cannot tell “transfer ownership” from “set reserve param” from the bytes — both are calldata to the same Safe.execTransaction selector with different inner payloads). The signers confirmed.
The compromise didn’t happen on October 16; it happened over the weeks before, machine by machine, until three signers — enough to meet the 3-of-11 threshold — were simultaneously implanted with the malware variant that would activate during a Safe-signing session.
2.4 Why this isn’t a Solidity case study
You can read Radiant’s contracts top to bottom and you will not find the bug. The bug is:
- A client-side malware payload on each compromised signer’s MacBook, intercepting the WebUSB / WebHID bridge between Safe UI and the Ledger, swapping calldata at the moment it was forwarded to the device.
- A UX gap in Ledger’s clear-signing coverage: Safe’s
execTransactioncalldata is structurally complex (a wrapped sub-call) and Ledger has not historically decoded it. - An operational-security gap in Radiant’s signing protocol: no second-device verification of the Safe-tx-hash, no air-gapped signers, no separation of signer machines from developer machines.
The case study below treats these as primary findings — because in 2024 they are.
3. The Vulnerability — Three Layers
The Radiant compromise required three failures to chain. Remove any one of them and the attack does not execute. An auditor’s job is to see all three.
3.1 Layer 1 — signer device compromise
The DPRK actor cluster Mandiant tracks as UNC4736 is known for elaborate social-engineering chains targeting DeFi engineers, often via fake recruiter / “Web3 job opportunity” pretexts. [verify specific Radiant initial-access vector — Mandiant’s report describes the cluster’s general TTPs and notes the Radiant compromise was consistent with them; the exact lure email or document is not always disclosed]
The reported pattern for compromise of Radiant signer machines [verify against Mandiant report and Radiant post-mortem]:
- Signers were approached via Telegram / LinkedIn / job-board with what appeared to be legitimate professional opportunities (a contract gig, a smart-contract review request, a podcast invitation).
- The pretext eventually involved opening an attachment or running a binary (a “PDF reader”, a “signed Zoom client”, a “smart-contract test harness” — variations of the AppleJeus family).
- The binary deployed a macOS-targeted implant (“
InletDrift” or related; the family has multiple labelled variants) that established persistence and gave the operator the ability to drop further-stage payloads on command. - The implant remained dormant for weeks. Operators waited for the right moment.
- When the operator detected a Safe-signing session (via browser-process monitoring, WebHID traffic, or scheduled trigger), the implant deployed a final-stage payload that intercepted communication between the Safe UI and the connected Ledger.
The key insight for auditors: this is not “I clicked a phishing link”-grade compromise. It is multi-month, well-resourced, pretext-driven access tailored to engineering targets. Generic anti-phishing training does not protect against it. The defense is architectural — assume the developer machine is compromised, and design signing so that compromise doesn’t translate to a signature.
3.2 Layer 2 — calldata substitution at the WebHID boundary
Once on the signer’s machine at signing time, the malware’s job was straightforward:
Safe UI (browser, Chrome/Firefox)
│ "Please sign this Safe execTransaction":
│ to=PoolAddressesProvider
│ data=setReserveParam(USDC, ...) ← what signer sees
▼
WebHID / Connect Kit bridge
│
▼ [MALWARE INTERPOSES HERE]
│ data=execTransaction(target=PoolAddressesProvider,
│ value=0,
│ data=transferOwnership(0xATTACKER),
│ ...) ← what device gets
▼
Ledger Nano (USB)
│
▼ Displays: "Sign Ethereum transaction"
To: <Safe address>
Data: 0x6a761302...<long hex> ← BLIND HEX
User clicks Approve
│
▼
Signed transaction returned to Safe UI
│
▼ Signature collected; once threshold reached, anyone can submit
The bridge between the Safe UI and the device is the integration point. Safe’s web UI assembles the EIP-712 SafeTx struct and a corresponding execTransaction calldata, signs the EIP-712 hash with the hardware wallet, and submits. The malware lives in the glue — the WebHID / Connect-Kit library on the user’s machine, or the user’s browser extension, or a userland MITM hooked into Chrome’s process.
Crucially:
- The signer sees the Safe UI’s rendered transaction, which is HTML in a browser tab on the compromised machine — trivially rewritten by the same malware.
- The Ledger sees the bytes that arrive over USB — bytes the malware controls.
- The two never have to match.
- The Ledger has no independent reference for “what the user actually intended”. Its only input is the USB stream.
This is the textbook “display does not equal sign” failure mode. The mitigation is for the device to render the calldata in a form the human can verify — clear-signing.
3.3 Layer 3 — blind-signing on the hardware wallet
A Ledger Nano S/X presented with an Ethereum eth_sign or eth_signTransaction request displays:
- the destination address
- the value (ETH amount)
- the gas parameters
- and either the decoded calldata (if a clear-signing plugin or registered EIP-712 schema covers this call), or raw hex otherwise
For a Safe execTransaction(...) call, the outer transaction’s to is the Safe contract itself. The Safe’s execTransaction selector (0x6a761302) wraps an inner call: (target, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, signatures). The inner data is itself encoded calldata to whatever the real target is (e.g., transferOwnership(...)).
So the signer’s Ledger displays:
Review transaction
To: 0x<safe address>
Data: 0x6a76130200000000000000000000000000<...thousands of hex chars...>
A typical signer cannot decode this by hand, on the device, in the moment. The standard practice has been to trust the Safe UI to have set the calldata correctly — i.e., to rely on the very surface that the malware has rewritten.
What clear-signing of Safe transactions would have looked like on the device:
Review SafeTx
Safe: 0xRadiantMultisig...
Target: 0x<contract>
Function: transferOwnership(address)
Argument 0: 0xATTACKER...
Operation: CALL
Hash: 0xdeadbeef... (Safe-tx-hash)
Confirm? Yes / No
If any one of the three compromised signers had been signing through a device or workflow that displayed this, they would have aborted. The drain doesn’t happen.
This is why the case study’s primary lesson is clear-signing. It is the structural defense (analogous to CEI for reentrancy): if the device renders the meaningful fields, the malware’s display rewrite is irrelevant — the bytes the device sees are the bytes the user must approve.
3.4 The trust-boundary diagram
Signer's brain
│
▼ "I intend: routine emissions adjustment"
[Trust boundary A]
│
▼
Safe UI (web browser on signer's MacBook)
│ Renders: "setReserveParam(USDC, ...)" ← what signer sees
[Trust boundary B — MALWARE LIVES HERE]
│
▼
WebHID / Connect Kit bridge
│ Forwards: execTransaction(...transferOwnership(0xATTACKER)...)
[Trust boundary C — the device-USB boundary]
│
▼
Ledger Nano
│ Displays: raw hex (blind-signing)
[Trust boundary D — the human eye]
│
▼ Signer presses "Approve"
Signature returned
The Radiant attack exploited boundaries B and D simultaneously: corrupted what crossed B and exploited the human’s inability to read D. Closing either one closes the attack.
4. The Attack — Timeline
[All timeline numbers below: verify against Mandiant report, Radiant post-mortems on Medium, and Halborn’s Oct-Nov 2024 writeups. Some elements are inferred from the general MO of UNC4736 because Radiant did not disclose every detail.]
4.1 Reconnaissance and access (weeks–months prior)
- UNC4736 operators identified Radiant signers — likely via on-chain analysis of the Safe owner addresses, then OSINT linking those addresses to real-world engineering identities (Twitter, GitHub, LinkedIn).
- Pretexted contact began through professional channels. Targets were approached individually with tailored lures: contract jobs, technical collaborations, podcast appearances. [verify specific Radiant lures]
- Initial-access payloads (macOS-targeted, AppleJeus-family) deployed across three signer machines independently over a window. Each signer believed they had downloaded a legitimate artifact (PDF, signed binary, code sample).
- Implants achieved persistence and beaconed to operator infrastructure.
4.2 Staging (days–weeks prior)
- Operators monitored signer activity, building a profile: which engineer signs which kinds of transactions, what the team’s signing rhythm looks like, when emissions-parameter signing rounds happen.
- A Safe-transaction-substitution module was prepared, targeting Radiant’s specific Safe address and the
transferOwnershipselector of Radiant’sPoolAddressesProvider. - The attack window was synchronized to a planned, internally-coordinated parameter-update transaction so that signers would expect to sign and would not raise alarms when the signing request appeared.
4.3 Execution (October 16, 2024)
- Ops team queued a routine parameter-adjustment transaction in the Safe UI.
- Three signers received the signing request, opened the Safe UI in their browsers, reviewed the displayed transaction (which the malware did not need to rewrite because it was the legitimate display), clicked “Sign”, and confirmed on their Ledgers.
- At the WebHID handoff, the malware swapped the transaction payload. Each Ledger received a different transaction: a call to
Safe.execTransaction(...)with inner calldatatransferOwnership(0xATTACKER). - Each Ledger displayed the Safe-tx hex blob (blind-signing). Each signer pressed Approve.
- The malware collected the signatures and submitted the malicious Safe execution to the chain. Threshold met.
transferOwnership(0xATTACKER)executed on Radiant’sPoolAddressesProvider. Attacker now controlled the protocol.
4.4 Drain (minutes following)
The mechanics of the drain are the boring part — once the attacker has owner privileges on an Aave-fork lending protocol, they have multiple primitives [verify exact path used]:
- Upgrade implementations: replace the
LendingPool(orPoolin v3) implementation with a malicious one that exposes a “drain to attacker” function, or simply waives access controls on existing transfer functions. - Set reserve parameters: weaponize collateral factor / LTV settings to enable a borrowing-without-collateral path.
- Direct withdrawals: depending on the admin surface, some Aave forks expose direct treasury-withdrawal admin functions that let the owner pull reserve balances.
Radiant’s drain was [verify whether via implementation upgrade or via admin parameter abuse — Halborn’s writeup suggests upgrade] executed across Arbitrum and BNB Chain pools in the minutes following the ownership transfer. By the time on-chain monitoring tools (Forta watchlists, Tenderly alerts, Discord-routed Etherscan alerts) raised the alarm and the team responded, the loot was bridged and en route to mixers.
4.5 Response (hours–days following)
- Radiant team paused remaining contracts and disabled markets where they retained admin control [verify which contracts were paused vs. lost-control].
- Public disclosure within hours on Twitter/X and Discord.
- Coordinated with Mandiant, Halborn, ZeroShadow, SEAL 911, and other incident responders for attribution and tracing.
- Mandiant’s later report attributed to UNC4736 [verify formal attribution language].
- Tornado-equivalent mixers and cross-chain bridge addresses associated with the drain were monitored; some downstream addresses sanctioned by OFAC under the existing DPRK regime.
- Recovery of funds was minimal [verify].
5. Reproduction — Why You Can’t, and What to Do Instead
This is the case study where the on-chain reproduction is not the lesson. You cannot rebuild the Radiant compromise in a Foundry test because the bug lives in the signer’s machine and the device-USB bridge, not in Solidity. Attempting to mock it would teach the wrong reflexes.
Instead, this section gives you the two operational exercises that build the right muscle: (1) verify a Safe transaction hash on an independent device, and (2) decode execTransaction calldata by hand.
5.1 What “verifying a Safe transaction” actually means
A Safe transaction is uniquely identified by its Safe-tx-hash: an EIP-712 structured hash over the SafeTx struct fields:
SafeTx(
address to,
uint256 value,
bytes data,
uint8 operation, // 0 = CALL, 1 = DELEGATECALL
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 nonce
)
The safeTxHash is keccak256(EIP712Domain || SafeTxTypeHash || encodedFields). The hardware wallet’s signature is over this hash. If two devices independently compute the same hash from the same struct fields, you have agreement.
The verification protocol that defeats the Radiant attack:
- Signer opens Safe UI on their primary workstation and prepares the transaction. UI displays “Confirm: setReserveParam(…)“.
- Signer reads the displayed fields off the Safe UI and enters them by hand (or via QR scan) into a separate, dedicated verification tool on a different device (a phone, an air-gapped laptop, a Keystone/Cypherock secondary device).
- The verification tool recomputes the
safeTxHashfrom the entered fields. - The Ledger, when it receives the EIP-712 sign request, displays the
safeTxHashit is about to sign (Ledger does support this for EIP-712 in many flows — verify it does for the SafeTx domain on the relevant firmware). - Signer compares: hash on the verification tool == hash on the Ledger display. If yes, sign. If no, abort.
The crucial property: the verification tool and the Ledger both compute hashes from inputs that have to match the user’s stated intent. The malware on the primary workstation can rewrite what the Safe UI displays and what is shipped over WebHID, but it cannot rewrite the user’s verbal/visual entry into a second device.
5.2 Hand-decoding execTransaction calldata
Below is the exercise you should be able to perform in 5 minutes during an audit of any protocol with a treasury Safe.
Suppose the malicious Safe transaction Radiant’s signers approved had inner calldata equivalent to:
transferOwnership(0xATTACKER)
The full calldata received by the Ledger would be a call to Safe.execTransaction(...) whose data parameter contains the encoded transferOwnership selector + argument. Schematically (with placeholder addresses):
0x6a761302 // execTransaction selector
000000000000000000000000<target_contract_20_bytes> // to
0000000000000000000000000000000000000000000000000000000000000000 // value (0)
0000000000000000000000000000000000000000000000000000000000000140 // data offset (0x140 = 320)
0000000000000000000000000000000000000000000000000000000000000000 // operation (0 = CALL)
0000000000000000000000000000000000000000000000000000000000000000 // safeTxGas (0 — using estimateGas)
0000000000000000000000000000000000000000000000000000000000000000 // baseGas
0000000000000000000000000000000000000000000000000000000000000000 // gasPrice
0000000000000000000000000000000000000000000000000000000000000000 // gasToken (0 = ETH)
0000000000000000000000000000000000000000000000000000000000000000 // refundReceiver
0000000000000000000000000000000000000000000000000000000000000260 // signatures offset
0000000000000000000000000000000000000000000000000000000000000024 // data length (0x24 = 36)
f2fde38b // transferOwnership(address) selector
000000000000000000000000<attacker_address_20_bytes> // attacker arg
...
Key insight for the auditor: the inner data field is the one that says what’s really happening. The to field tells you the target contract; the first 4 bytes of data tell you the function selector; the remaining 32-byte chunks are the arguments.
If you can read these by eye, or if your verification tool can decode and display them, you cannot be tricked by a substituted payload. The Radiant signers’ device displayed exactly this kind of blob and they had no tool to decode it in the loop.
5.3 Operational lab — building a Safe verification flow
A practical, audit-grade verification workflow for any multisig with significant value:
- Maintain a known-good ABI registry of every contract the Safe will ever call (the protocol’s own contracts; LayerZero adapters; common dependencies). Store it in a versioned repo, signed by maintainers.
- Verification utility on a second device (phone or air-gapped laptop) that:
- Accepts pasted (or QR-scanned) raw Safe
execTransactioncalldata. - Decodes inner calldata against the ABI registry.
- Renders human-readable fields: “Target: PoolAddressesProvider. Function: transferOwnership(address). Argument 0: 0x…“.
- Recomputes the
safeTxHashand displays it.
- Accepts pasted (or QR-scanned) raw Safe
- Signing protocol:
- Signer prepares tx in Safe UI on primary machine.
- Signer reads tx fields aloud (or shares them via a side channel) to themselves on the second device.
- Verification tool decodes and shows human-readable rendering and
safeTxHash. - Ledger receives sign request; Ledger displays its computed hash.
- Hashes must match across all three: Safe UI displayed intent + verification tool decode + Ledger hash.
- Only then approve.
- For very-high-value Safes: at least one signer should be on an air-gapped machine (no network, transactions transferred via QR-coded PSBT-style flow); the air-gap means the malware cannot reach in to substitute calldata.
Open-source tools that move toward this today [verify current state]:
- Safe Hash / Safe Wallet’s own “verify on Ledger” feature — some firmware versions of Ledger now have partial Safe clear-signing.
- Tenderly — simulates the transaction; if the simulation shows
transferOwnershipinstead ofsetReserveParam, the alarm fires before signing. - Rabby, Frame — wallet-level pre-sign simulation showing asset movements and storage writes.
- MetaMask + Blockaid — wallet-level pre-sign warning for known scam patterns.
safe-tx-hashes-util/ community CLI tools that recompute and displaysafeTxHash.
Pick one. Make it part of the protocol’s signing runbook. Have all signers practice it on a testnet Safe before signing anything in production.
5.4 Foundry sanity-test — the smart-contract side IS clean
For completeness, a Foundry test that demonstrates the contracts behaved correctly — i.e., that there is nothing to “patch” on-chain:
// test/RadiantOwnershipTransfer.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
interface IRadiantOwnable {
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
}
/// @notice Showing the contracts did exactly what they were told.
/// The bug is upstream, in the signer's machine.
contract RadiantContractsBehavedCorrectlyTest is Test {
address constant MULTISIG = 0xRadiantMultisig000000000000000000000000;
address constant ATTACKER = 0xATTACKER0000000000000000000000000000000;
IRadiantOwnable provider;
function setUp() public {
// Fork pre-attack state
vm.createSelectFork("arbitrum", /* block just before drain */ 0);
provider = IRadiantOwnable(/* PoolAddressesProvider */ address(0));
}
function test_transferOwnership_works_when_owner_calls_it() public {
// Pre-state: multisig is owner.
assertEq(provider.owner(), MULTISIG);
// The Safe, as owner, calls transferOwnership. This is the
// contract behaving exactly as designed. The "bug" is that the
// Safe was tricked into making this call.
vm.prank(MULTISIG);
provider.transferOwnership(ATTACKER);
assertEq(provider.owner(), ATTACKER);
}
function test_transferOwnership_reverts_when_non_owner_calls() public {
vm.prank(address(0xdeadbeef));
vm.expectRevert(); // "Ownable: caller is not the owner" or equivalent
provider.transferOwnership(ATTACKER);
}
}The point of including this test: smart-contract verification confirms the contracts were correct. The auditor delivering this test as the “Radiant finding” would have been technically right and operationally wrong. The actual finding is up at the signing-UX layer.
6. Aftermath
6.1 Immediate response
In the hours after the drain, Radiant’s team executed the standard DeFi-incident playbook:
- Public disclosure on X/Twitter, Discord, governance forum.
- Markets paused where possible.
- Engagement with security firms: Mandiant (attribution), Halborn (forensics), ZeroShadow (tracing), SEAL 911 / Chainalysis (sanctions / freezing).
- Coordination with USDC/USDT issuers to freeze loot held in stablecoins. Circle and Tether do honor protocol-level freeze requests for known-malicious addresses; the speed of bridging meant only a small fraction was caught this way [verify].
- Coordination with cross-chain bridge operators to flag transfers.
6.2 Attribution and Mandiant’s report
Mandiant (now Google Cloud’s incident-response arm) published an analysis attributing the Radiant compromise to UNC4736, a DPRK-aligned actor cluster that overlaps with what other vendors call AppleJeus / Lazarus. [verify exact Mandiant report title and publication date — it was published in late 2024 / early 2025]
Key elements of the attribution [verify all]:
- Initial-access TTPs matched UNC4736’s known pattern of pretexted job/contract lures targeting Web3 engineers.
- Implant code signatures matched samples from previous UNC4736-attributed incidents (DMM Bitcoin, etc.).
- On-chain laundering patterns — bridge hops, mixer addresses, OTC off-ramps — matched the cluster’s known infrastructure.
- The attribution is high confidence per Mandiant’s standard rubric, and the U.S. Treasury has separately attributed multiple 2024 DeFi hacks to DPRK-linked actors via OFAC sanctions actions.
6.3 Industry response — clear-signing pressure
Post-Radiant, several industry shifts accelerated:
- Ledger publicly emphasized its clear-signing roadmap and pushed for protocol-side adoption of EIP-712 schemas registered in their clear-signing repository.
- Safe added or accelerated features for transaction simulation and Safe-tx-hash verification in the Safe Wallet web UI.
- GridPlus Lattice1 and Keystone marketed their device-side ability to decode
execTransactioncalldata (Keystone has had this for some time; GridPlus extended its decoder coverage). - Audit firms began routinely listing “blind-signing of Safe transactions” as an operational finding in protocol audits — even when the contracts were clean.
- Insurance (Nexus Mutual etc.) — premiums for protocols with low-threshold Safes on shared developer-machine signers rose [verify].
- SEAL and similar community-response orgs published refreshed multisig hygiene guides explicitly citing Radiant as the worst-case demonstration.
6.4 The protocol’s recovery
Radiant relaunched [verify state at time of writing] with a substantially redesigned operational-security posture:
- Higher signing threshold.
- Dedicated air-gapped signing machines.
- Mandatory multi-device Safe-tx-hash verification.
- Tenderly / Phalcon simulation as a pre-signing requirement.
- Reduced cross-chain admin surface.
TVL has not returned to pre-hack levels. The protocol’s reputational damage is the lasting cost; the financial loss was bounded by the drain itself.
6.5 The bigger lesson — multisig is not magic
For most of DeFi’s history, “we use a 3-of-5 / 4-of-7 multisig” has functioned as a security trump card in pitch decks: we don’t have a single point of failure. Radiant proved that threshold is a function of independent compromise, and if all signers run the same OS, the same browser, the same wallet extension, on the same kind of machine, with the same blind-signing UX, the threshold collapses. A 3-of-11 where the 11 are interchangeable from an attacker’s perspective is, threat-model-wise, almost a 1-of-1 — the attacker just has to repeat the same compromise three times.
The defense is diversity: different OSes, different hardware-wallet vendors, different jurisdictions, different devices used only for signing, and clear-signing UX across all of them.
7. Lessons for Auditors
7.1 Clear-signing is the CEI of signer security
In §3 we framed the three layers of the Radiant attack. The one that is structurally fixable with no runtime cost — analogous to CEI for reentrancy — is clear-signing on the device.
Clear-signing means: the hardware wallet decodes the calldata (and EIP-712 struct) into human-readable fields and renders them on its own trusted display, so the user is shown — and must approve — the actual content of the transaction, not a hash or hex blob.
For Safe execTransaction, this means the device renders:
- Target contract (decoded against the Safe owner’s known ABI registry, ideally).
- Function name and selector.
- Argument values, with type-correct formatting.
- The Safe-tx-hash.
- Operation type (CALL vs DELEGATECALL — DELEGATECALL especially must be flagged).
For protocols asking users to sign EIP-712 payloads, this means the device renders:
- The decoded EIP-712 fields with human-readable labels.
The defense is structural: if the device shows the right thing, no malware on the host machine can trick the signer. The audit finding for any protocol whose admin Safe uses Ledger Nano (or any device without Safe-aware clear-signing) is:
Critical operational finding: Safe
execTransactioncalldata is rendered as raw hex on the connected hardware wallets, leaving signers blind to the actual content of the transaction. A host-machine compromise (malware substituting calldata at the WebHID/Connect Kit boundary, as in Radiant Capital October 2024) cannot be detected by a blind-signing flow. Recommend: (a) adopt clear-signing-capable devices for all signers (GridPlus Lattice1, Keystone 3 Pro, future Ledger firmware with Safe support), or (b) implement out-of-band Safe-tx-hash verification on a second device for every signature.
7.2 Threshold is a function of independent compromise — not a count
A 3-of-11 sounds robust. It isn’t, if the 11 share an attack surface.
The auditor’s worksheet for any protocol multisig:
| Diversification axis | What to verify |
|---|---|
| OS | At least 2 of: macOS, Linux, Windows. Single-OS Safes are catastrophic. |
| Hardware wallet vendor | At least 2 of: Ledger, Trezor, GridPlus, Keystone, Cypherock. Multiple vendors prevent firmware-level supply-chain compromise from being a single point of failure. |
| Geographic / jurisdictional | Signers in different countries; resists coordinated subpoena, kinetic threats, and time-zone-synchronized phishing. |
| Identity / professional role | Signers from different organizations and roles (not all internal engineers); a successful pretext for one community signer is unlikely to work on another. |
| Machine separation | Signing machine ≠ development machine. Code workflow is malware-rich (npm install, untrusted deps, browser extensions). Signing machine should be hardened, minimal, and ideally air-gapped. |
| Browser / extension stack | Not all signers on Chrome + MetaMask. Diversity reduces single-software-bug catastrophic exposure. |
| Signing UX | Not all signers using the same Connect-Kit / Bridge library. |
The effective threshold is the minimum number of “compromise events” an attacker needs to execute given the actual diversity profile. For Radiant’s 3-of-11 with the documented homogeneity, the effective threshold was likely “three compromises of one well-defined target type” — within DPRK’s operational scope.
For high-value Safes (TVL > $50M), the recommendation is:
- Threshold ≥ ceil(2N/3). (For 11 signers, that’s 8. Three compromised owners cannot meet threshold.) [verify exact convention — some shops use ceil(3N/5).]
- At least two signers on truly air-gapped infrastructure.
- At least two signers on different hardware-wallet vendors.
- At least one signer is a third-party security professional (independent eyes).
7.3 Verify the Safe-tx-hash on an independent device — every time
The single highest-leverage operational practice. If the same hash appears on:
- The primary machine’s Safe UI,
- The Ledger / hardware-wallet display,
- An independent verification tool on a phone or air-gapped laptop (which decodes calldata and computes the hash from inputs),
then a malware-mediated substitution must compromise all three devices simultaneously to succeed. That is a meaningfully harder operation than compromising one MacBook.
This protocol should be mandatory for any signature that:
- Calls
transferOwnership,upgradeTo,upgradeToAndCall,setImpl,grantRole(DEFAULT_ADMIN_ROLE, ...). - Uses DELEGATECALL (Safe
operation=1). - Targets any contract not on the Safe’s pre-vetted ABI registry.
- Has a value transfer over a configurable threshold (e.g., > $100k).
For low-value, routine signatures (a fee parameter tweak on a small testnet Safe), the protocol can be more relaxed. But for ownership / upgrade / treasury, always.
7.4 Pre-signing simulation as runtime defense
Beyond clear-signing on the device, transaction simulation before signing catches a different class of malware substitution: ones where the malicious calldata is technically rendered correctly but its effect is non-obvious.
Tenderly, Phalcon, Rabby’s built-in simulator, MetaMask’s Blockaid integration — these tools execute the transaction against the current chain state and report:
- State changes (which storage slots in which contracts are modified).
- Asset movements (token in/out for the signer and for the protocol).
- Role changes (owner, admin, etc.).
- Reverts and warning patterns.
A Radiant signer running Tenderly simulation pre-sign would have seen, on their primary machine: “This transaction will change PoolAddressesProvider.owner from 0xRadiantMultisig to 0xATTACKER.” Alarm.
Caveat: the malware could in principle also rewrite the Tenderly output rendered in the browser. The defense composes with clear-signing and second-device verification — no single layer is sufficient. Defense in depth is the only correct posture for high-value signing.
7.5 Audit the off-chain runbook
For every protocol with a treasury Safe or upgrade authority, the audit deliverable should now include a signing-runbook review:
- Who signs? Are they identified (where possible)? Where do they keep their key? What machine do they sign on?
- What’s the proposal-flow checklist? Does someone other than the proposer review every transaction?
- Is there a hard rule for ownership-changing or upgrade transactions vs. routine parameter changes?
- Is there a mandatory second-device verification step?
- Are simulations run pre-sign?
- Is there an emergency rollback if a signature is detected to have been compromised before threshold is met?
- Is there an out-of-band, authenticated channel (signed Slack, Signal with verified safety numbers) for signers to confirm they each intended to sign the same thing?
This is the runbook half of “multisig audit”. Without it, the contract half is a polished kitchen door on a house with no walls.
7.6 Why this case generalizes
Radiant is not unique. The same shape recurred — with variations — in:
- WazirX (July 2024, ~$235M): multisig signer compromise, attributed to DPRK-linked actor; some elements of UI substitution. [verify]
- DMM Bitcoin (June 2024, ~$305M): similar attribution; key-handling compromise. [verify]
- Ronin Bridge (March 2022, ~$625M): nine-validator multisig with five compromised via Lazarus social engineering of Sky Mavis engineers. The Radiant pattern, vintage 2022.
- Multiple smaller 2024 protocols whose post-mortems read identically: routine Safe transaction, signers blind-signed, ownership transferred.
The pattern has stabilized to the point that “DPRK is targeting our multisig signers” is a credible default threat-model assumption for any protocol with > $50M TVL. Auditors should treat it as standard scope.
8. What You Would Have Caught (Pre-Attack Auditor Exercise)
Imagine you are doing an operational-security review of Radiant Capital in September 2024 — a month before the drain. You have access to the contracts (clean), the Safe configuration, signer identities (within reason), the signing runbook (if it exists), and the team’s general security posture. Here is what should fire on a careful review.
8.1 Immediate fires (under 60 seconds, from the Safe page on app.safe.global)
| Signal | Why it fires |
|---|---|
| Threshold of 3 on a Safe controlling ~$300M TVL | Convention for $50M+ value at stake is ceil(2N/3). 3-of-11 is “operational convenience”, not security. Three independent compromises = total loss. |
| All signer addresses are EOA addresses with developer-shaped on-chain activity | Cross-referencing addresses with on-chain history reveals deploys, npm-pay transactions, GitHub commit links — these are the same machines used for protocol development. Code work is malware-rich. |
| No transaction-simulation in the documented signing workflow | If the runbook does not mandate Tenderly / Rabby / similar pre-sign simulation, the team is signing blind. |
| No second-device Safe-tx-hash verification step in the runbook | If signers don’t independently compute the hash, host-machine compromise = total compromise. |
| Hardware wallets in use are documented as Ledger Nano S/X | Ledger does not clear-sign Safe execTransaction calldata; signers are blind-signing. (Audit finding regardless of process.) |
8.2 Secondary signals (next 30 minutes)
- No documented incident-response playbook for “we just signed a malicious transaction”: the moment of detection between “signing” and “execution” can be a minute or hours; if the team doesn’t have a procedure (cancel via overriding-nonce Safe tx, alert other signers, contact SEAL/Chainalysis), they will lose that window.
- No on-chain monitoring on the Safe address with paging alerts: every owner-change or implementation-upgrade Safe execution should page the on-call engineer within seconds. Forta + PagerDuty; Tenderly Alerts; Defender Sentinels. Radiant’s drain was visible on Etherscan minutes before being noticed; faster monitoring narrows the window.
- No threshold-differentiated signing policy: a routine fee-parameter change should not have the same signing process as
transferOwnership. High-impact targets should require additional steps (a 24-hour cooling-off, an out-of-band confirmation call between signers, a published Snapshot signal to the community). - No air-gapped emergency signer: if all signers are online and a coordinated compromise is detected, there is nobody who can sign a counter-transaction (e.g., a
transferOwnershipback to a known-safe address) from outside the blast radius. - Signing UX uses Safe’s hosted UI: even without malware, this is a frontend trust dependency (cf. BadgerDAO 2021). Recommend self-hosted or IPFS-pinned Safe UI for sensitive flows.
8.3 Tertiary signals (architectural)
PoolAddressesProvidertransferOwnershiphas no timelock: a single-step ownership transfer is the worst-case primitive. IftransferOwnershiphad been gated by a 48-hour timelock with mandatory on-chain proposal, the Radiant drain has a 48-hour window during which the community would have seen the attacker address as pending-owner. Even a 1-hour timelock would have made the difference.- No emergency pause-guardian distinct from owner: there is no role that can pause the protocol independently of the owner. When the owner is the attacker, the protocol cannot be paused. Best practice: a separate pause-guardian multisig with a different signer set.
- Upgrade authority and treasury authority concentrated in the same Safe: separating “can upgrade contracts” from “can move treasury funds” forces an attacker to compromise two Safes for a full drain. Radiant’s owner-Safe could do both.
8.4 The 60-second auditor verdict
“Critical operational findings on Radiant Capital admin Safe: (1) Threshold (3-of-11) too low for value at stake (~$300M). Recommend ceil(2N/3) = 8. (2) Hardware wallets blind-sign Safe
execTransaction— signers cannot distinguish ownership-transfer from parameter-change. Recommend GridPlus or Keystone; or out-of-band Safe-tx-hash verification on a second device for every signature. (3) No pre-signing transaction simulation in documented runbook. Recommend mandatory Tenderly/Phalcon simulation step. (4) Signer machines double as developer machines (npm-rich, browser-rich, malware-exposed). Recommend dedicated air-gapped signing devices, at minimum for ownership/upgrade transactions. (5)transferOwnershipis single-step with no timelock. Recommend 48-hour timelock with on-chain proposal queueing. (6) No on-chain monitoring with paging on owner/upgrade events. Recommend Forta + PagerDuty integration.Estimated exploitability under nation-state adversary (DPRK / UNC4736-class): high. Pattern matches DMM Bitcoin June 2024, Ronin March 2022. Severity: critical (full protocol takeover possible from three independent signer-machine compromises).”
That report, delivered in September 2024, would have changed the trajectory. Not because the team didn’t know about hardware wallets or threshold theory — they did — but because the operational checklist, broken out item by item, makes the gap impossible to hand-wave away.
8.5 What this teaches about audit methodology
The Radiant case rewrites the auditor’s job description in a way that some firms still resist.
-
Smart-contract audit is a necessary, not sufficient, deliverable. A protocol that ships with a perfect contract audit and a 3-of-11 signing-on-laptops setup is no more secure than one with a buggy contract and a 5-of-7 air-gapped setup. The total-system view is what matters.
-
The signing UX is part of the threat model. It is no longer reasonable for an auditor to say “out of scope” to “how do your signers verify what they’re signing”. If your engagement is “audit Radiant for security”, the Safe operational posture is in scope by default.
-
Threat-model nation-state actors for high-TVL protocols. DPRK has 50M+ TVL is in scope for them. Treating UNC4736 as a theoretical adversary is no longer credible.
-
Operational findings deserve the same severity language as contract findings. “Critical: signers blind-sign Safe transactions” is as severe as “Critical: reentrancy in
withdraw”. Treat them with parity in the report. -
The audit report should grade the runbook, not just the code. If the protocol has no documented signing runbook, that itself is the finding. If the runbook exists but does not require second-device verification for ownership transactions, that is the finding. If the runbook requires it but the team admits they don’t always follow it, that is the finding.
The modern auditor’s playbook — Spearbit, Trail of Bits, OpenZeppelin, Halborn, Cantina — has been migrating toward this stance since Ronin 2022 and accelerated dramatically after Radiant 2024. If you are entering the field in 2025–2026, assume the operational layer is your job until told otherwise.
9. References
Radiant Capital — official and team communications
- Radiant Capital — official post-mortem (Medium / blog) — multiple updates between October 2024 and early 2025: https://medium.com/@RadiantCapital [verify exact post URLs — Radiant published a series of disclosure posts on Medium and on their forum]
- Radiant Capital forum / governance discussion of the incident — community response, signers’ statements: https://community.radiant.capital [verify URL]
Attribution and threat-actor profiles
- Mandiant / Google Cloud — UNC4736 analysis [verify exact title and URL — published as part of M-Trends or as standalone report late 2024 / early 2025]: https://www.mandiant.com/resources/blog
- U.S. Treasury / OFAC sanctions actions — DPRK-linked DeFi laundering addresses sanctioned through 2024: https://home.treasury.gov/policy-issues/financial-sanctions/recent-actions
- Chainalysis — 2024 Crypto Crime Report — DPRK section covers the year’s DeFi compromises in aggregate: https://www.chainalysis.com/reports/
Security-firm post-mortems and analyses
- Halborn — “Explained: The Radiant Capital Hack” (October 2024 explainer): https://www.halborn.com/blog/post/explained-the-radiant-capital-hack-october-2024
- SlowMist — Radiant Capital incident analysis (Twitter thread + blog): https://slowmist.medium.com [verify exact post]
- PeckShield — incident alerts on Radiant: https://twitter.com/PeckShieldAlert (October 16, 2024)
- BlockSec — Radiant incident timeline and trace: https://twitter.com/BlockSecTeam (October 16, 2024)
- SEAL 911 — multisig hygiene guidance updated post-Radiant: https://github.com/security-alliance [verify repo path]
Multisig security and clear-signing — primary docs
- Safe Wallet — execTransaction docs and SafeTx hash specification: https://docs.safe.global/sdk/protocol-kit
- Safe — “Verifying Safe transactions” guide: https://help.safe.global [verify article slug]
- Ledger — clear-signing repository (EIP-712 schemas): https://github.com/LedgerHQ/clear-signing
- GridPlus Lattice1 — multisig signing flow docs: https://docs.gridplus.io
- Keystone — Safe integration docs: https://docs.keyst.one
Sibling cases (for comparative pattern study)
- Ronin Bridge (March 2022) — Sky Mavis validator compromise via Lazarus social engineering of engineers. The Radiant pattern, vintage 2022. See Case-Ronin-Bridge-2022 [if note exists].
- WazirX (July 2024) — multisig compromise of a centralized exchange’s hot-wallet Safe. [verify links]
- DMM Bitcoin (June 2024) — Japanese exchange ~$305M loss, DPRK attribution. [verify]
- Heco / HTX Bridge (November 2023) — bridge admin compromise. [verify]
- BadgerDAO (December 2021) — frontend-injection variant of the same “user signed something they didn’t see” pattern. See Case-BadgerDAO-Frontend-2021 [if note exists].
- Multichain (July 2023) — operator-side key compromise; different threat model but same lesson on operational concentration.
Long-form retrospectives
- The Block — “Inside the Radiant Capital Hack” (long-form journalism, late 2024): https://www.theblock.co [verify exact article]
- Rekt News — Radiant Capital entry: https://rekt.news/radiant-capital-rekt-2 [verify URL — Rekt sometimes uses “rekt-2” suffix for protocols hit twice; Radiant was previously hit by a smaller flash-loan incident in January 2024, so the second-hit naming may apply]
- CertiK — Radiant Capital incident review: https://www.certik.com/resources [verify post]
Auditor methodology updates referencing Radiant
- Trail of Bits — “Auditing multisig signing UX” [verify if published]
- Spearbit — “Operational findings in protocol audits” (blog post or annual review): https://spearbit.com/blog [verify]
- OpenZeppelin — security advisory on multisig hygiene post-Radiant: https://blog.openzeppelin.com [verify]
Etherscan / Arbiscan / BscScan key addresses
- Radiant Capital
PoolAddressesProvider(Arbitrum) [verify address] - Radiant Capital admin Safe [verify address — was a Gnosis Safe deployed at a documented public address]
- Attacker addresses — chains across Arbitrum, BNB Chain, Ethereum [verify on-chain trace]
- Drain transactions — bundled in the protocol post-mortem [verify tx hashes]
Tooling references
- Tenderly — transaction simulation: https://tenderly.co
- Phalcon (BlockSec) — transaction explorer / simulator: https://phalcon.blocksec.com
- Rabby — wallet with built-in pre-sign simulation: https://rabby.io
- Blockaid — wallet-security middleware: https://www.blockaid.io
- Forta — on-chain monitoring: https://forta.org
- OpenZeppelin Defender — Sentinel monitoring: https://www.openzeppelin.com/defender
Last updated: 2026-05-16 See also: Tuan-12-Wallet-AA-Key-Management · Tuan-14-Governance-DAO-Security · Tuan-13-Frontend-dApp-Infrastructure · Case-Parity-Multisig-2017 · Case-BadgerDAO-Frontend-2021 · Case-The-DAO-Reentrancy-2016 · audit-checklist-master · Roadmap · References