Aurellion Labs Hack Analysis: Diamond Proxy Uninitialized Facet Exploit
On May 12, 2026, Aurellion Labs, an Arbitrum-based DeFi protocol, suffered a security incident resulting in a loss of approximately $456K USDC.
Overview
On May 12, 2026, Aurellion Labs, an Arbitrum-based DeFi protocol, suffered a security incident resulting in a loss of approximately $456K USDC. The root cause was an incomplete facet upgrade: the protocol's own owner had previously added a new SafeOwnable facet to the EIP-2535 Diamond Proxy - registering an initialize(address) selector - but omitted the post-cut initializer call, leaving the OpenZeppelin _initialized storage slot at zero. An attacker observed this uninitialized state, called initialize() to seize ownership, injected a fund-draining logic facet, and swept outstanding user USDC approvals.
Technical Analysis of the Exploit
Incident Overview
Time of Incident: May 12, 2026.
Target Chain: Arbitrum One.
Total Loss: ~456K USDC.
Pre-condition - Owner Upgrade (Incomplete): 0x1868d5d48ffc6b4c226208fcd2a5f70654456a77a173f81fe514ae15fabc86d1
Attack Transaction: 0x19cbafae517791e7e73403313d70440abf60558350e419df05c04f816998fe0a
Victim Contract (Diamond Proxy): 0x0adc63e71b035d5c7fdb1b4593999fa1f296f1b2
Malicious Facet: 0x3CA79C1cf29B8d19F7c643bB6E6bc9c49762E70f
Attacker Address (EOA): 0x9F49591a3bf95B49cD8d9477b4481Ce9da68d5Ca
Root Cause
The vulnerability arose from two compounding weaknesses in Aurellion Labs’ EIP-2535 Diamond Proxy implementation.
First, the protocol’s own owner performed a facet upgrade - transaction 0x1868d5...bc86d1 - adding a new SafeOwnable facet under action Add with five selectors including initialize(address). The diamondCut call set target = address(0) and data = "", meaning no initializer was invoked as part of the upgrade.
Second, the proxy's existing ownership had been set through a path that never wrote to the _initialized slot, so the guard remained at zero. The proxy treated itself as uninitialized, leaving initialize(address) open to any caller.
By invoking initialize() and supplying an attacker-controlled address, the adversary successfully overwrote the _owner record at the LibDiamond storage slot (0xc8fcad8d...131f) and assumed full administrative control over the proxy - including the authority to make further diamondCut calls.
Attack Flow
The attack executed across two transactions on Arbitrum One.
Pre-condition: Incomplete Owner Upgrade
Prior to the exploit, the protocol’s owner called diamondCut (transaction 0x1868d5...bc86d1) to add a new SafeOwnable facet at 0x3CA79C1cf29B8d19F7c643bB6E6bc9c49762E70f with action Add across five selectors:
0xc4d66de8-initialize(address)0x8da5cb5b-owner()0xf2fde38b-transferOwnership(address)0x79ba5097-acceptOwnership()0x715018a6-renounceOwnership()
The target was address(0) and data was empty - the post-cut initialize() call was never made. This was the critical omission: the Diamond now had a live initialize(address) selector registered against a facet whose OpenZeppelin guard slot had never been written, leaving initialization open to any caller.
Ownership Takeover
In transaction 0x19cbaf...98fe0a, the attacker called initialize(0x4D7759…8F4d7e) on the Diamond Proxy, passing an attacker-controlled intermediary contract as the new owner argument. Because the _initialized slot was 0, the guard passed without reversion. An OwnershipTransferred event was emitted, transferring control away from the legitimate owner (0x1866Fd4a9e15E0005480b5171B63b43d2d507698) to the attacker’s intermediary (0x4D7759e69cC973D338a1ea2fDB125C2b818F4d7e). An Initialized event immediately followed, updating the version counter to 1 and permanently sealing the initialization path against any future re-entry.
Malicious Facet Injection
Now holding proxy ownership through the intermediary contract, the attacker invoked diamondCut - the EIP-2535 mechanism used to register or replace logic facets - to append a custom, attacker-controlled facet (0x3ca79c1cf29b8d19f7c643bb6e6bc9c49762e70f) to the proxy. A DiamondCutExecuted event confirmed the registration of proposal 0x1133cd…3fa548. This facet exposed a pullERC20 function capable of issuing arbitrary transferFrom calls on behalf of the proxy, against any token for which the proxy held a user-granted allowance.
User Fund Drainage
Because users had previously granted USDC allowances to the Aurellion proxy for legitimate protocol interactions, the attacker used pullERC20 to sweep those outstanding balances:
450,999.72 USDC drained from
0x2e933518068b1CFC9746d94762Ef2EDDD39c60483.00 USDC drained from
0xa90714a15D6e5C0EB3096462De8dc4B22E01589A1.28 USDC drained from
0xEceD2D37e5EDCFc67ffB74c655416F893d20793E
Fund Extraction
The proxy consolidated approximately 456,442.53 USDC - inclusive of residual in-contract balance - and forwarded the full amount to the attacker’s primary wallet (0x9F49591a3bf95B49cD8d9477b4481Ce9da68d5Ca), completing the exploit without any additional transactions.
Conclusion
A legitimate facet upgrade, one skipped initialize() call, and complete protocol takeover - this incident shows how small deployment gaps become catastrophic in a Diamond Proxy, where facets can be swapped independently but must each be initialized atomically.
In EIP-2535, the gap between “facet registered” and “initializer called” is narrow in implementation and devastating in consequence. The fix is unambiguous: either encode the initialize() call directly in the diamondCut data field so it executes atomically, or permanently close it with _disableInitializers() in the facet’s constructor. A deferred follow-up transaction is not acceptable.
The attack also illustrates a second-order risk in any approval-based model: the attacker swept funds not from the protocol’s treasury but from users’ wallets, exploiting pre-existing USDC allowances on the now-compromised contract. Contract vulnerabilities can become user losses - revoking stale token approvals remains an important habit.




